虚函数和多态的概念
- 虚函数:在基类中使用
virtual
关键字声明的成员函数。虚函数的目的是为了让派生类可以重写(override)这个函数,从而提供不同的实现。
- 多态:多态是指同一个操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在 C++ 中,多态主要通过虚函数和指针或引用的动态绑定来实现。通过基类的指针或引用调用虚函数时,会根据指针或引用实际指向的对象类型来决定调用哪个类的虚函数实现,这就是多态性的体现。
实现原理
- 虚函数表:当一个类中包含虚函数时,编译器会为这个类生成一个虚函数表(vtable)。虚函数表是一个存储类成员虚函数地址的数组。每个包含虚函数的类或从包含虚函数的类派生而来的类都有自己的虚函数表。
- 虚指针:每个对象在内存布局中会包含一个指向其所属类虚函数表的指针,称为虚指针(vptr)。当通过基类指针或引用调用虚函数时,程序会首先根据对象的虚指针找到对应的虚函数表,然后在虚函数表中找到实际要调用的虚函数地址,最后调用该函数。这就是动态绑定的过程,它发生在运行时,根据对象的实际类型决定调用哪个函数。
代码示例
#include <iostream>
// 基类 Shape
class Shape {
public:
// 虚函数 draw
virtual void draw() const {
std::cout << "Drawing a Shape." << std::endl;
}
};
// 派生类 Circle
class Circle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a Circle." << std::endl;
}
};
// 派生类 Rectangle
class Rectangle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a Rectangle." << std::endl;
}
};
int main() {
Shape* shapePtr1 = new Circle();
Shape* shapePtr2 = new Rectangle();
shapePtr1->draw(); // 调用 Circle 的 draw 函数
shapePtr2->draw(); // 调用 Rectangle 的 draw 函数
delete shapePtr1;
delete shapePtr2;
return 0;
}
动态绑定过程解释
- 在
main
函数中,创建了 Circle
和 Rectangle
对象,并分别用 Shape
类型的指针 shapePtr1
和 shapePtr2
指向它们。
- 当调用
shapePtr1->draw()
时,由于 draw
是虚函数,程序首先通过 shapePtr1
指向对象的虚指针找到 Circle
类的虚函数表。
- 在
Circle
类的虚函数表中找到 draw
函数的地址,并调用 Circle
类中重写的 draw
函数。
- 同理,当调用
shapePtr2->draw()
时,程序通过 shapePtr2
指向对象的虚指针找到 Rectangle
类的虚函数表,然后调用 Rectangle
类中重写的 draw
函数。这就是通过基类指针实现多态的动态绑定过程。