多态与虚函数
翻译整理自 cppreference - 虚函数。
1. 静态多态 vs 动态多态
- 静态:函数重载、模板、CRTP——编译期决定
- 动态:虚函数——运行期决定
2. virtual 虚函数
class Shape {
public:
virtual double area() const { return 0; }
virtual ~Shape() = default; // 多态基类必虚析构
};
class Circle : public Shape {
public:
Circle(double r) : r_(r) {}
double area() const override { // override 关键字
return 3.14 * r_ * r_;
}
private:
double r_;
};
class Square : public Shape {
public:
Square(double s) : s_(s) {}
double area() const override { return s_ * s_; }
private:
double s_;
};
void print(Shape* s) {
std::cout << s->area(); // 动态派发
}
print(new Circle(1));
print(new Square(2));3. override 与 final
override 让编译器检查是否真的覆盖(C++11):
class D : public Base {
public:
void f() override; // 必须真的覆盖,否则报错
};final 禁止再覆盖或继承:
class Base final {}; // 不能再继承
class D : public Base {
public:
void f() final; // 派生类不能再覆盖
};4. 纯虚函数与抽象类
class Shape {
public:
virtual double area() const = 0; // 纯虚函数
virtual ~Shape() = default;
};
// Shape s; // ❌ 抽象类不可实例化
class Circle : public Shape {
public:
double area() const override { return 1.0; }
};
Circle c; // OK
5. 虚析构函数
多态基类必须虚析构,否则 delete base_ptr 不会调用派生析构:
class Base {
public:
virtual ~Base() = default;
};6. RTTI:dynamic_cast 与 typeid
Shape* s = new Circle(1);
if (auto c = dynamic_cast<Circle*>(s)) {
// 安全向下转换成功
}
#include <typeinfo>
std::cout << typeid(*s).name(); // 类型名
RTTI 需虚函数支持,且开销较大。推荐用
static_cast配合自定义类型标签。
7. 虚函数表 vtable
每个含虚函数的类都有一个 vtable,对象内部存有指向 vtable 的指针。调用虚函数时通过 vtable 间接查找目标函数。
class A {
public:
virtual void f();
};
// sizeof(A) 通常 = sizeof(void*) = 8
8. 隐藏(不叫覆盖)
非虚同名函数在派生类会隐藏基类版本:
class Base { public: void f(int); };
class D : public Base {
public:
void f(double); // 隐藏 Base::f(int)
};
D d;
d.f(1); // 调用 D::f(double)
d.Base::f(1); // 显式调用基类
用 using Base::f; 引入:
class D : public Base {
public:
using Base::f; // 把基类 f 引入派生
void f(double);
};9. 协变返回类型
虚函数覆盖可返回更具体的类型:
class Base {
public:
virtual Base* clone() const;
};
class D : public Base {
public:
D* clone() const override; // 返回 D*,更具体
};10. 性能权衡
- 虚函数调用比普通函数多一次间接寻址
- 难以被编译器内联
- 在性能关键路径上慎用虚函数
小结
虚函数是 C++ 实现 OOP 多态的核心,配合 override/final 可让代码更安全。