#include <iostream>
// 抽象基类Shape
class Shape {
public:
// 纯虚函数draw
virtual void draw() const = 0;
};
// 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();
shapePtr1->draw();
delete shapePtr1;
// 通过抽象基类引用实现多态调用
Circle circle;
Shape& shapeRef = circle;
shapeRef.draw();
return 0;
}
- 运行时多态的实现:
- 在上述代码中,通过
Shape
基类指针shapePtr1
指向Circle
对象,调用draw()
函数时,实际执行的是Circle
类中重写的draw()
函数。同样,通过Shape
基类引用shapeRef
绑定到Circle
对象,调用draw()
函数也会执行Circle
类中的draw()
函数。这就是运行时多态,程序在运行时根据对象的实际类型来决定调用哪个类的虚函数。
- 底层机制 - 虚函数表:
- 当一个类包含虚函数(如
Shape
类中的draw()
纯虚函数)时,编译器会为这个类生成一个虚函数表(vtable)。虚函数表是一个函数指针数组,每个元素是一个虚函数的地址。
- 每个包含虚函数的类的对象都会有一个隐藏的指针(vptr),指向该类的虚函数表。当对象创建时,vptr 被初始化,指向该对象所属类的虚函数表。
- 当通过基类指针或引用调用虚函数时,程序首先通过对象的vptr找到对应的虚函数表,然后根据虚函数表中函数指针的偏移量,找到并调用实际对象类型对应的虚函数。例如,当
shapePtr1
指向Circle
对象时,shapePtr1
所指向对象的vptr指向Circle
类的虚函数表,在Circle
类的虚函数表中draw()
函数的实现地址被调用,从而实现了运行时多态。