面试题答案
一键面试代码实现
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a Shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing a Circle" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
std::cout << "Drawing a Rectangle" << std::endl;
}
};
int main() {
Shape* shapePtr1 = new Circle();
Shape& shapeRef1 = *shapePtr1;
shapePtr1->draw();
shapeRef1.draw();
Shape* shapePtr2 = new Rectangle();
Shape& shapeRef2 = *shapePtr2;
shapePtr2->draw();
shapeRef2.draw();
delete shapePtr1;
delete shapePtr2;
return 0;
}
运行时多态的实现原理
- 虚函数表(VTable):当一个类中包含虚函数时,编译器会为这个类创建一个虚函数表。虚函数表是一个存储虚函数地址的数组。对于基类
Shape
,它的虚函数表中存放了draw
函数的地址(这里是基类draw
函数的地址)。当派生类Circle
和Rectangle
重写了draw
函数时,它们各自的虚函数表中draw
函数的地址会被替换为派生类中draw
函数的地址。 - 虚指针(VPtr):每个包含虚函数的类的对象,都会有一个虚指针。这个虚指针指向该对象所属类的虚函数表。当通过基类指针或引用调用虚函数时,程序会首先通过虚指针找到对应的虚函数表,然后在虚函数表中找到实际要调用的虚函数的地址,并执行该函数。
例如,当shapePtr1
指向Circle
对象时,shapePtr1
所指向对象的虚指针会指向Circle
类的虚函数表,此时调用draw
函数,就会调用Circle
类中重写的draw
函数。同理,当shapePtr2
指向Rectangle
对象时,会调用Rectangle
类中重写的draw
函数,从而实现了运行时多态。