MST
星途 面试题库

面试题:C++ 中虚基类和虚函数在实现多态时的作用及区别

请详细阐述在 C++ 中虚基类和虚函数分别是如何为实现多态机制做出贡献的,并说明它们之间的主要区别。
14.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚基类对多态机制的贡献

  1. 避免菱形继承中的数据冗余:在菱形继承结构中,若不使用虚基类,从多个路径继承相同基类会导致基类数据成员在最终派生类中有多份拷贝。虚基类使得从不同路径继承而来的虚基类子对象只有一份实例,保证了对象内存布局的唯一性,为多态提供了正确的对象结构基础。例如:
class A {
public:
    int data;
};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};

在上述代码中,D类对象中A类的数据成员data只有一份拷贝,这确保了在多态操作中对该数据成员的访问一致性。 2. 统一虚基类子对象的初始化:虚基类的初始化由最底层的派生类负责,这种统一的初始化方式避免了因多重继承路径不同而导致的初始化冲突,保证了虚基类子对象状态的一致性,有利于在多态环境下正确处理对象。

虚函数对多态机制的贡献

  1. 动态绑定:虚函数实现了运行时的动态绑定。当通过基类指针或引用调用虚函数时,实际调用的函数版本取决于指针或引用所指向的对象的实际类型,而非指针或引用本身的类型。例如:
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;
    }
};
Shape* shapePtr = new Circle();
shapePtr->draw();

在上述代码中,虽然shapePtrShape*类型,但由于draw是虚函数,实际调用的是Circle类中的draw函数版本,实现了多态行为。 2. 实现多态接口:虚函数为派生类提供了一个统一的接口,派生类可以根据自身需求重写虚函数,从而实现不同的行为。这使得在处理不同类型的派生类对象时,可以使用相同的基类接口进行操作,增强了代码的灵活性和可扩展性。

虚基类和虚函数的主要区别

  1. 概念用途
    • 虚基类:主要用于解决多重继承中的菱形继承问题,避免数据成员的冗余和不一致性,侧重于对象的内存布局和初始化。
    • 虚函数:主要用于实现运行时的多态,通过动态绑定根据对象实际类型调用合适的函数版本,侧重于函数调用的动态性和行为的多样性。
  2. 作用时机
    • 虚基类:在编译时和对象初始化时起作用,确定对象的内存结构和虚基类子对象的初始化方式。
    • 虚函数:在运行时起作用,根据对象的实际类型决定调用哪个函数版本。
  3. 影响范围
    • 虚基类:影响整个继承体系中对象的内存布局,对所有从虚基类派生的类都有影响。
    • 虚函数:主要影响类及其派生类中虚函数的调用行为,每个类对虚函数的重写是独立的。