获取sizeof对象的成员

时间:2015-07-14 22:46:40

标签: c++ class sizeof vtable members

有一个对象,我需要找到其成员的大小。我特别要求对象的大小没有它的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更新他的答案,或者我会在如何处理的问题上添加补充答案多重继承。

2 个答案:

答案 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

请参阅https://ideone.com/g5SZwk

因为我们知道编译器正在使用vptrs,所以vptrs的位置在这些“图纸”中很明显。

关于C ++中的继承

非虚拟继承

当不使用虚拟继承时,基类子对象继承图始终是以最派生类为根的树,即使子类型图不是树:

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()
  • 覆盖

此处gBottom名称的查找会因含糊不清而失败,因此在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