具有虚拟指针和继承的 CPP 类大小

cpp class size with virutal pointer and inheritance

本文关键字:CPP 继承 虚拟 指针      更新时间:2023-10-16
class A{
virtual void a();
};  
class B : A{
virtual void a();
};
class C{
virtual void a();
};
class E : A, C{
virtual void a();
};
int main(){
std::cout << (sizeof(B)) << "n"; // 4
std::cout << (sizeof(C)) << "n"; // 4
std::cout << (sizeof(E)) << "n"; // 8
}

在 32 位系统中 Linux

为什么 sizeof(B( 和 sizeof(C( 都是 4

对于 C 类,它有一个虚函数,因此在 C 类中隐藏了一个 4 字节的虚拟指针

但为什么B类的大小也是4。我认为它在 B 类中存在两个指针,一个是 B 本身,因为 B 类有一个虚函数,一个是 A 的。

那么E也有同样的问题呢?

任何帮助不胜感激

不,每个使用虚函数的对象中只有一个 vtable 指针,如果虚函数是在类本身中定义的,或者该类派生自另一个使用虚函数的类,则独立地存在。

编译器生成的是一个函数指针表,因此每个类(不是实例/对象(都有自己的。在您的示例中,您有一个用于类 A 的表,一个用于类 B 的表,依此类推。在每个对象/实例中,您都有一个 vtable 指针。此指针仅指向表。如果通过类指针调用虚函数,则间接寻址在 vtable 指针上,而不是在 vtable 本身上。

因此,类的每个实例只保留一个指向此类的 vtable 的 vtable。如您所见,这会导致您编写的每个类的每个实例的大小相同。

在多重继承的情况下,您将获得多个 vtable 指针。这里已经给出了更详细的答案: vtable 和多重继承

顺便说一句:标准并不能保证你有一个 vtable 和一个 vtable 指针,如果结果是我们从语义中期望的,每个编译器都可以做它想做的事。但是,通过 vtable 指针到表中指向函数的指针的双重间接寻址是典型的实现。

对于单一继承,派生类 B 只是在虚拟表中再插入一个条目。 对于多重继承,派生类 E 有 2 个虚拟表指针。

进一步:C++MI(多重继承(的虚拟表布局