MST

星途 面试题库

面试题:C++虚函数与继承中的多态实现

假设有一个基类`Shape`,包含虚函数`draw()`,以及派生类`Circle`和`Rectangle`继承自`Shape`并重写`draw()`函数。请编写一段代码,展示如何通过基类指针或引用实现多态调用`draw()`函数,并解释运行时多态在这种场景下是如何实现的,包括虚函数表和虚指针的工作原理。
43.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

代码实现

#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;
}

运行时多态的实现原理

  1. 虚函数表(VTable):当一个类中包含虚函数时,编译器会为这个类创建一个虚函数表。虚函数表是一个存储虚函数地址的数组。对于基类Shape,它的虚函数表中存放了draw函数的地址(这里是基类draw函数的地址)。当派生类CircleRectangle重写了draw函数时,它们各自的虚函数表中draw函数的地址会被替换为派生类中draw函数的地址。
  2. 虚指针(VPtr):每个包含虚函数的类的对象,都会有一个虚指针。这个虚指针指向该对象所属类的虚函数表。当通过基类指针或引用调用虚函数时,程序会首先通过虚指针找到对应的虚函数表,然后在虚函数表中找到实际要调用的虚函数的地址,并执行该函数。

例如,当shapePtr1指向Circle对象时,shapePtr1所指向对象的虚指针会指向Circle类的虚函数表,此时调用draw函数,就会调用Circle类中重写的draw函数。同理,当shapePtr2指向Rectangle对象时,会调用Rectangle类中重写的draw函数,从而实现了运行时多态。