获取对象成员的大小

Get the sizeof Object's Members

有一个对象的成员,我需要找到它的大小。我特别要求对象的大小 without 它是 v-table 考虑的。另外,我不能修改它,所以我不能利用 .

除了对每个成员硬编码 sizeof 求和之外,在 C++ 中是否有这方面的规定?

我知道 v-tables 不是 C++ 强制要求的。我也知道我对这些信息所做的任何事情都会被广泛考虑 "bad form"。这个问题只是在询问是否可能,而不是认可这种行为。


它引起了我的注意. What I wanted to learn with this question was how to cast a parent to a child. That is, I wanted to preserve the child's v-table, but copy the parent's member variables:

已接受的答案确实为我提供了执行此操作所需的信息。但是,尽管我认为 http://whosebug.com curiousguy .

最糟糕的行为是地方病

从已接受的答案到多重继承的扩展显然是显而易见的,但答案应该包含它是有效的。作为权宜之计,我添加了一个如何处理多重继承的实例:http://ideone.com/1QOrMz I will request that user2596732 更新他的答案,或者我将添加一个关于如何处理多重继承的问题的补充答案。

没有。

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

为了发现多态对象的布局,你可以比较指向成员对象的指针;简单的演示程序 "draws" 带有符号的对象的布局:

  • 小写字母是数据成员的名字
  • 大写字母是碱基的名称class
  • *表示对象的一部分不属于任何成员子对象或基class子对象

每个字节都有一个符号(根据定义,char 是一个字节)。

vptr(s) 必须在 "empty" space 中,space 未分配给数据成员。

类型定义为:

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 的位置在这些 "drawings".

中很明显

关于 C++ 中的继承

非虚继承

当不使用虚拟继承时,基础 class 子对象继承图始终是一棵以最派生的 class 为根的树,即使子类型化图不是树也是如此:

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

此处在 Bottom 中查找名称 g 会因歧义而失败,因此在 Bottom 中使用不合格的 g 将是错误的。

虚拟继承

当使用虚拟继承时,基础class子对象继承是以最派生class为唯一终端的无环有向图:

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