- 虚函数表指针存储位置
- 在C++中,当一个类包含虚函数时,该类的对象中会额外存储一个虚函数表指针(vptr)。对于基类对象,vptr指向基类的虚函数表。当派生类继承基类并覆盖部分虚函数时,派生类对象也有一个vptr,这个vptr指向派生类的虚函数表。
- 通常,vptr存储在对象的起始位置(不同编译器可能有差异,但大多如此)。这意味着对象的内存布局首先是vptr,然后是对象的数据成员。
- 内存开销变化
- 基类:如果基类只包含虚函数和数据成员,其内存开销除了数据成员占用的空间外,还需额外存储vptr,一般在32位系统中vptr占4字节,64位系统中占8字节。
- 派生类:派生类除了继承基类的数据成员和vptr外,如果有自己新的数据成员,会增加相应的内存开销。并且由于覆盖了部分虚函数,派生类有自己的虚函数表,虽然虚函数表本身不占用对象的内存空间,但vptr指向它。
- 代码示例
#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
并增加了新的数据成员derivedData
。sizeof(Derived)
通常为24字节(8字节的vptr + 4字节的baseData
+ 4字节的derivedData
+ 8字节的内存对齐)。
- 通过
Base* basePtr = new Derived();
,basePtr
虽然是Base
类型指针,但指向Derived
对象,调用basePtr->virtualFunction()
会调用Derived
类中覆盖后的虚函数,这体现了多态性,而背后是vptr和虚函数表的机制在起作用。