MST

星途 面试题库

面试题:C++虚函数表指针与类继承体系下的内存开销关系

考虑一个C++类继承体系,基类中有虚函数,派生类继承并覆盖部分虚函数。请详细分析在这种情况下,虚函数表指针在不同类对象中的存储位置以及由此带来的内存开销变化,结合代码示例说明。
23.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 虚函数表指针存储位置
    • 在C++中,当一个类包含虚函数时,该类的对象中会额外存储一个虚函数表指针(vptr)。对于基类对象,vptr指向基类的虚函数表。当派生类继承基类并覆盖部分虚函数时,派生类对象也有一个vptr,这个vptr指向派生类的虚函数表。
    • 通常,vptr存储在对象的起始位置(不同编译器可能有差异,但大多如此)。这意味着对象的内存布局首先是vptr,然后是对象的数据成员。
  2. 内存开销变化
    • 基类:如果基类只包含虚函数和数据成员,其内存开销除了数据成员占用的空间外,还需额外存储vptr,一般在32位系统中vptr占4字节,64位系统中占8字节。
    • 派生类:派生类除了继承基类的数据成员和vptr外,如果有自己新的数据成员,会增加相应的内存开销。并且由于覆盖了部分虚函数,派生类有自己的虚函数表,虽然虚函数表本身不占用对象的内存空间,但vptr指向它。
  3. 代码示例
#include <iostream>

class Base {
public:
    virtual void virtualFunction() {
        std::cout << "Base::virtualFunction" << std::endl;
    }
    int baseData;
};

class Derived : public Base {
public:
    void virtualFunction() override {
        std::cout << "Derived::virtualFunction" << std::endl;
    }
    int derivedData;
};

int main() {
    std::cout << "Size of Base object: " << sizeof(Base) << " bytes" << std::endl;
    std::cout << "Size of Derived object: " << sizeof(Derived) << " bytes" << std::endl;

    Base* basePtr = new Derived();
    basePtr->virtualFunction();

    delete basePtr;
    return 0;
}
  • 在上述代码中:
    • Base类包含一个虚函数virtualFunction和一个数据成员baseData。在64位系统下,sizeof(Base)通常为16字节(8字节的vptr + 4字节的int类型baseData + 4字节的内存对齐)。
    • Derived类继承自Base,覆盖了virtualFunction并增加了新的数据成员derivedDatasizeof(Derived)通常为24字节(8字节的vptr + 4字节的baseData + 4字节的derivedData + 8字节的内存对齐)。
    • 通过Base* basePtr = new Derived();basePtr虽然是Base类型指针,但指向Derived对象,调用basePtr->virtualFunction()会调用Derived类中覆盖后的虚函数,这体现了多态性,而背后是vptr和虚函数表的机制在起作用。