多态与虚函数
virtual 虚函数、vtable 原理、纯虚函数/抽象类、dynamic_cast
多态与虚函数
多态让你通过基类指针调用子类的方法——运行时决定执行哪个版本。这是面向对象的灵魂。
学完本章你将: 掌握 virtual 虚函数、vtable 原理、纯虚函数/抽象类、dynamic_cast。
多态基础
cpp
#include <iostream>
class Animal {
public:
virtual void speak() const { // virtual = 可以被子类重写
std::cout << "动物叫声\n";
}
virtual ~Animal() = default; // 虚析构——至关重要!
};
class Dog : public Animal {
public:
void speak() const override {
std::cout << "汪汪!\n";
}
};
class Cat : public Animal {
public:
void speak() const override {
std::cout << "喵喵!\n";
}
};
int main() {
Animal *animals[] = {new Dog(), new Cat()};
for (auto *a : animals) {
a->speak(); // 运行时决定——Dog 说汪汪,Cat 说喵喵
}
// 清理
for (auto *a : animals) delete a;
return 0;
}
vtable 原理(简化)
每个有虚函数的类有一张虚函数表(vtable),对象中存一个指向这张表的指针(vptr):
Dog 对象:
[vptr] → Dog::vtable → &Dog::speak
Cat 对象:
[vptr] → Cat::vtable → &Cat::speak
调用 a->speak():
1. 通过 vptr 找到 vtable
2. 在 vtable 中找到 speak 的地址
3. 调用它
纯虚函数与抽象类
cpp
class Shape { // 抽象类——不能实例化
public:
virtual double area() const = 0; // 纯虚函数
virtual ~Shape() = default;
};
class Circle : public Shape {
double r;
public:
Circle(double radius) : r(radius) { }
double area() const override { return 3.14159 * r * r; }
};
// Shape s; // ❌ 抽象类不能实例化
Circle c(5); // ✅
⚠️ 基类的析构函数必须声明为 virtual——否则通过基类指针 delete 子类对象时,子类的析构函数不会被调用,导致资源泄漏。