类的大小 - C ++

时间:2012-02-13 11:09:50

标签: c++ function virtual sizeof

我有以下关于对象大小的代码:

class A 
{ 
public: 
    int _i; 
    virtual int getI () = 0; 
    int setI (int i); 
}; 
class B : public A 
{ 
public: 
    int getI (); 
    virtual int setI (int i); 
}; 

class C : public B 
{ 
public: 
    int _i; 
    int getI (); 
    int setI (int i); 
}; 

int main () 
{ 
    B b; 
    C c; 
} 

为什么大小     C c; 是12?尺寸计算中包含哪些部分?

5 个答案:

答案 0 :(得分:8)

sizeof(int A::_i) + sizeof(int C::_i) + sizeof(pointer to virtual table)

所有这些部分的大小都与实现有关,在您的情况下,每个部分的大小为4。

答案 1 :(得分:5)

任何类的大小都取决于实现,但我会 猜测你是32位机器,C类包含4字节 vptr和两个四字节intA::_iC::_i)。

答案 2 :(得分:1)

对象的大小将是特定于平台的。例如,在64位平台上,我希望大小为24字节。什么构成对象的大小有点棘手。它由各种组件组成:

  • 大小的明显组成部分是数据成员:在您的情况下,您在层次结构中的某个位置有两个int,即这将贡献2 * sizeof(int)
  • 众所周知的隐藏组件是指向“vtable”的指针,即指向某种数据结构的指针,该数据结构处理虚拟函数的调用方式。这通常会产生指针大小。
  • 大多数人可能完全忽略了多重继承的隐藏指针,特别是当对象涉及虚拟基类时:要使对象看起来好像是特定层次结构中的对象,它将包含多于“vtable”指针
  • 虽然被许多人忽略但更为人所知的是“填充”,即用于确保数据成员与CPU优选的地址对齐的隐藏字节。通常,如果存在这种大小的相应基本类型,则优选对齐大致是给定系统上高速缓存行大小的类型的大小。也就是说,通常最大对齐是16个字节。
  • 最后,我可以想到一个有空类的有趣的:由于子对象需要有不同的地址,每个空类将被视为至少有一个字节大,除非空类是基类,在这种情况下它可能与其他基地共享相同的地址。

大多数隐藏的东西都不适用,但是对于你的班级,你有2 * sizeof(int) + sizeof(T*)用于访问虚拟功能表的合适类型。

答案 3 :(得分:0)

C c;的大小实际上是实现定义的。如果您有任何实际依赖于大小的代码,则此代码非常错误,并且无论何时切换编译器都可能会中断。

现在回答您的所有问题:您可能认为C的大小与int中包含的C相同,或者您认为它的大小为int来自C的{​​1}}加上A的{​​1}}。

这两种猜测都是错误的,原因有两个:

  • 您的结构中可能存在所谓的填充。有时类型需要与某些边界对齐。为了强制执行这些对齐,编译器会在字段之间引入一些“浪费”空间区域,以使它们保留在这些位置。你永远不能依赖这个填充量。

  • 还有另一点,我主要认为你的老师想要告诉你:如果你写c.getI(),计算机必须知道要调用哪种方法,即是否从{{{ 1}},AB。这些信息需要存储在某个地方。此信息的存储为您的结构添加了一些额外的大小,但您永远不能依赖于将添加多少。有些人可能会试图告诉您这只是使用一个指针存储,但这是不正确。允许编译器使用尽可能多的空间来存储这些信息。出于效率原因,大多数编译器只使用一个指针,但是如果依赖于此,那么对于执行此操作的编译器来说,代码将是错误的。

如果您想了解更多信息,只需谷歌“虚拟方法调用”,您就可以找到一些针对此用例的常见实现示例。

答案 4 :(得分:0)

我认为你使用的是32位编译器。 这是C类的内存布局:

class C size(12):
    +---
    | +--- (base class B)
    | | +--- (base class A)
 0  | | | {vfptr}
 4  | | | _i
    | | +---
    | +---
 8  | _i
    +---

C::$vftable@:
    | &C_meta
    |  0
 0  | &C::getI
 1  | &C::setI

在此基础上,您可以看到哪些部分符合班级规模。

您可以阅读有关虚拟功能,虚拟继承,虚拟表的更多信息,以了解它们的组织方式并为课堂规模做出贡献。

如果使用MVSC,则在编译时可以使用-d1reportAllClassLayout选项来查看类的布局。