运行时多态
1. 虚函数重写
虚函数重写是指在派生类中重新定义基类中已声明为虚函数的函数。
虚函数重写的工作原理:
- C++通过虚函数表(vtable)和虚表指针(vptr)实现运行时多态。
- 每个具有虚函数的类都有一个虚函数表,该表包含指向类中所有已定义虚函数的指针。
- 对象中包含一个指向该表的指针,称为虚表指针,它指向对象所属类的虚函数表。
虚函数表:
- 一个类如果有虚函数,编译器会为该类生成一个虚函数表,表中包含指向类中所有虚函数的指针。
虚表指针:
- 每个对象都有一个虚表指针,它是一个指向类虚函数表的指针。
多个派生类是否共享基类的虚函数表:
- 不共享。每个类都有自己的虚函数表,即使是从基类继承的虚函数,派生类的虚函数表也会包含这些函数的条目。
类的多个对象是否共享类的虚函数表:
- 是的,类的多个对象共享同一个类的虚函数表,但每个对象都有自己的虚表指针,指向同一个表。
案例代码:
class Base {
public:
virtual void show() {
cout << "Base show" << endl;
}
virtual ~Base() {}
};
class Derived : public Base {
public:
void show() override {
cout << "Derived show" << endl;
}
~Derived() {}
};
void func(Base* b) {
b->show(); // 运行时多态
}
int main() {
Base* b = new Derived();
func(b); // 输出 Derived show
delete b;
return 0;
}
2. 纯虚函数
纯虚函数是在基类中声明但没有定义的虚函数,它要求派生类必须提供具体的实现。
案例代码:
class Shape {
public:
virtual void draw() const = 0; // 纯虚函数
};
class Circle : public Shape {
public:
void draw() const override {
cout << "Drawing a circle" << endl;
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // 输出 Drawing a circle
delete shape;
return 0;
}
3. 抽象类
抽象类是包含至少一个纯虚函数的类。它不能被直接实例化,但可以作为其他类的基类。
案例代码:
class Animal {
public:
virtual void speak() const = 0; // 纯虚函数
};
class Dog : public Animal {
public:
void speak() const override {
cout << "Woof!" << endl;
}
};
int main() {
// Animal a; // 错误:Animal是抽象类,不能实例化
Dog d; // 正确:Dog是非抽象类,可以实例化
d.speak(); // 输出 Woof!
return 0;
}
4. 虚析构
虚析构是声明为虚的析构函数,它确保在删除基类指针时能够调用正确的析构函数。
案例代码:
class Base {
public:
virtual ~Base() {
cout << "Base destructor" << endl;
}
};
class Derived : public Base {
public:
~Derived() {
cout << "Derived destructor" << endl;
}
};
int main() {
Base* b = new Derived();
delete b; // 调用 Derived 的析构函数,然后调用 Base 的析构函数
return 0;
}
在上述代码中,即使通过基类指针删除派生类对象,也会按正确的顺序调用派生类和基类的析构函数。这是通过虚析构函数实现的,它确保了正确的资源清理。
作者:
hwaityd
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。