sky*_*oor 26 c++ virtual-functions objectsize
我对虚拟对象大小有一些疑问.
1)虚函数
class A {
public:
int a;
virtual void v();
}
Run Code Online (Sandbox Code Playgroud)
A类的大小是8字节....一个整数(4个字节)加上一个虚拟指针(4个字节)很清楚!
class B: public A{
public:
int b;
virtual void w();
}
Run Code Online (Sandbox Code Playgroud)
B级的大小是多少?我使用sizeof B测试,它打印12
这是否意味着只有一个vptr,即使B类和A类都有虚函数?为什么只有一个vptr?
class A {
public:
int a;
virtual void v();
};
class B {
public:
int b;
virtual void w();
};
class C : public A, public B {
public:
int c;
virtual void x();
};
Run Code Online (Sandbox Code Playgroud)
C的大小是20 ........
似乎在这种情况下,两个vptrs在布局中......这是怎么发生的?我认为两个vptrs一个用于A类,另一个用于B类....所以没有vptr用于C类的虚函数?
我的问题是,关于继承中vptrs数量的规则是什么?
2)虚拟继承
class A {
public:
int a;
virtual void v();
};
class B: virtual public A{ //virtual inheritance
public:
int b;
virtual void w();
};
class C : public A { //non-virtual inheritance
public:
int c;
virtual void x();
};
class D: public B, public C {
public:
int d;
virtual void y();
};
Run Code Online (Sandbox Code Playgroud)
A的大小是8个字节-------------- 4(int a)+ 4(vptr)= 8
B的大小是16个字节--------------没有虚拟它应该是4 + 4 + 4 = 12.为什么这里还有4个字节?B级的布局是什么?
C的大小是12个字节.-------------- 4 + 4 + 4 = 12.很清楚!
D的大小是32个字节--------------它应该是16(B类)+ 12(C类)+ 4(int d)= 32.是吗?
class A {
public:
int a;
virtual void v();
};
class B: virtual public A{ //virtual inheritance here
public:
int b;
virtual void w();
};
class C : virtual public A { //virtual inheritance here
public:
int c;
virtual void x();
};
class D: public B, public C {
public:
int d;
virtual void y();
};
Run Code Online (Sandbox Code Playgroud)
sizeof A是8
sizeof B是16
sizeof C是16
sizeof D是28是表示28 = 16(B类)+ 16(C类) - 8(A类)+ 4(这是什么?)
我的问题是,为什么在应用虚拟继承时会有额外的空间?
在这种情况下,对象大小的下面规则是什么?
虚拟应用于所有基类和部分基类时有什么区别?
Ter*_*fey 21
这是所有实现定义的.我正在使用VC10 Beta2.有助于理解这些东西的关键(虚函数的实现),您需要了解Visual Studio编译器中的秘密开关/ d1reportSingleClassLayoutXXX.我会在一秒钟内完成.
基本规则是对于任何指向对象的指针,vtable需要位于偏移量0处.这意味着多个vtable用于多重继承.
在这里结合问题,我将从顶部开始:
这是否意味着只有一个vptr,即使B类和A类都有虚函数?为什么只有一个vptr?
这就是虚函数的工作方式,您希望基类和派生类共享相同的vtable指针(指向派生类中的实现).
似乎在这种情况下,两个vptrs在布局中......这是怎么发生的?我认为两个vptrs一个用于A类,另一个用于B类....所以没有vptr用于C类的虚函数?
这是C类的布局,由/ d1reportSingleClassLayoutC报告:
class C size(20):
+---
| +--- (base class A)
0 | | {vfptr}
4 | | a
| +---
| +--- (base class B)
8 | | {vfptr}
12 | | b
| +---
16 | c
+---
Run Code Online (Sandbox Code Playgroud)
你是对的,有两个vtable,每个基类一个.这是它在多重继承中的工作方式; 如果C*被转换为B*,指针值将被调整8个字节.vtable仍然需要在偏移0处才能使虚函数调用起作用.
上述A类布局中的vtable被视为C类的vtable(当通过C*调用时).
B的大小是16个字节--------------没有虚拟它应该是4 + 4 + 4 = 12.为什么这里还有4个字节?B级的布局是什么?
这是此示例中B类的布局:
class B size(20):
+---
0 | {vfptr}
4 | {vbptr}
8 | b
+---
+--- (virtual base A)
12 | {vfptr}
16 | a
+---
Run Code Online (Sandbox Code Playgroud)
如您所见,有一个额外的指针来处理虚拟继承.虚拟继承很复杂.
D的大小是32个字节--------------它应该是16(B类)+ 12(C类)+ 4(int d)= 32.是吗?
不,36个字节.同样处理虚拟继承.本例中D的布局:
class D size(36):
+---
| +--- (base class B)
0 | | {vfptr}
4 | | {vbptr}
8 | | b
| +---
| +--- (base class C)
| | +--- (base class A)
12 | | | {vfptr}
16 | | | a
| | +---
20 | | c
| +---
24 | d
+---
+--- (virtual base A)
28 | {vfptr}
32 | a
+---
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么在应用虚拟继承时会有额外的空间?
虚基类指针,它很复杂.基类在虚拟继承中"组合".该类不是将基类嵌入到类中,而是具有指向布局中基类对象的指针.如果您有两个使用虚拟继承的基类("菱形"类层次结构),它们将指向对象中的相同虚拟基类,而不是具有该基类的单独副本.
在这种情况下,对象大小的下面规则是什么?
很重要的一点; 没有规则:编译器可以做任何需要做的事情.
最后的细节; 制作我正在编译的所有这些类布局图:
cl test.cpp /d1reportSingleClassLayoutXXX
Run Code Online (Sandbox Code Playgroud)
其中XXX是结构/类的子字符串匹配,您希望看到它的布局.使用此方法,您可以自己探索各种继承方案的影响,以及添加填充的原因/位置等.