有一个对象,我需要找到其成员的大小。我特别要求对象的大小没有它的v-table被考虑。另外,我无法修改它,因此我无法利用this answer。
除了为每个成员总结一个硬编码的sizeof
之外,C ++中是否有这样的规定?
我知道v-table不是C ++强制要求的。我也知道,我对这些信息所做的任何事都将被广泛认为是“糟糕的形式”。这个问题只是询问是否可能,而不是支持这种行为。
我注意到that I need to clarify this question。我想用这个问题学习的是如何将父母送给孩子。也就是说,我想保留孩子的v表,但要复制父成员变量:https://stackoverflow.com/a/31454039/2642059
接受的答案 为我提供了执行此操作所需的信息。但是,尽管我认为行为是http://stackoverflow.com curiousguy points out a shortcoming of the accepted answer的最坏情况所特有的。
从接受的答案到多重继承的扩展是显而易见的,但答案应该包含它是有效的。作为权宜之计,我添加了一个如何处理多重继承的实例:http://ideone.com/1QOrMz我会请求user2596732更新他的答案,或者我会在如何处理的问题上添加补充答案多重继承。
答案 0 :(得分:2)
为了发现多态对象的布局,可以比较指向成员对象的指针;简单的演示程序使用符号“绘制”对象的布局:
*
表示不属于任何成员子对象或基类子对象的对象的一部分每个字节都有一个符号(根据定义,char
是一个字节)。
vptr必须位于“空”空间,未分配给数据成员的空间。
类型定义是:
struct T {
virtual void foo();
int i;
};
struct U {
virtual void bar();
long long l;
};
struct Der : T, U {
};
struct Der2 : virtual T, U {
};
struct Der3 : virtual T, virtual U {
};
输出是:
sizeof void* is 4
sizeof T is 8
sizeof i is 4
i is at offset 4
layout of T is
****iiii
sizeof U is 12
sizeof U::l is 8
l is at offset 4
layout of U is
****llllllll
sizeof Der is 20
Der::i is at offset 4
Der::l is at offset 12
Der::T is at offset 0
Der::U is at offset 8
layout of Der is
TTTTiiiiUUUUllllllll
sizeof Der2 is 20
Der2::i is at offset 16
Der2::l is at offset 4
Der2::T is at offset 12
Der2::U is at offset 0
layout of Der2 is
UUUUllllllllTTTTiiii
sizeof Der3 is 24
Der3::i is at offset 8
Der3::l is at offset 16
Der3::T is at offset 4
Der3::U is at offset 12
layout of Der3 is
****TTTTiiiiUUUUllllllll
因为我们知道编译器正在使用vptrs,所以vptrs的位置在这些“图纸”中很明显。
当不使用虚拟继承时,基类子对象继承图始终是以最派生类为根的树,即使子类型图不是树:
struct Repeated {
virtual void f();
virtual void g();
};
struct Left : Repeated {
void g();
};
struct Right : Repeated {
void g();
};
struct Bottom : Left, Right {
void f();
};
子类型图是:
Left
/ \
Repeated Bottom
\ /
Right
子对象图是:
Left::Repeated --- Left
\
Bottom
/
Right::Repeated --- Right
这是非虚拟继承的关键效果:图形并不总是匹配。如果你不明白你不理解非虚拟继承!
这意味着从Bottom*
到Repeated*
的转化不明确。
在这个例子中:
Bottom::f()
会同时覆盖Left::Repeated::f()
和Right::Repeated::f()
。Left::Repeated::g()
被Left::g()
Right::Repeated::g()
被Right::g()
此处g
中Bottom
名称的查找会因含糊不清而失败,因此在g
中使用不合格的Bottom
会出错。
当使用虚拟继承时,基类子对象继承是一个非循环有向图,其中派生类最多的是一个唯一的终端:
struct Unique { virtual void f(); };
struct Left : virtual Unique { void f(); };
struct Right : virtual Unique { void f(); };
struct Bottom : Left, Right { void f(); };
此处所有其他f()
声明都会覆盖Unique::f()
。
此处子对象图与子类型图匹配:
Left
/ \
Unique Bottom
\ /
Right
答案 1 :(得分:0)
sizeof(Class)只包含一个VTable指针。
class A
{
public:
int a = 2;
int b = 2;
virtual void x() {
};
virtual void y() {
};
};
class B : public A
{
public:
int c = 2;
int d = 2;
virtual void y() {
};
};
class C : public A
{
public:
int c = 2;
int d = 2;
int e = 2;
virtual void x() {
};
};
所以对于这个例子,
cout << sizeof(A)-sizeof(void*) << endl;
cout << sizeof(B)-sizeof(void*) << endl;
cout << sizeof(C)-sizeof(void*) << endl;
应该给你正确的答案。 8 16 20