Get the sizeof Object's Members

2019-08-07 13:12发布

There is an object who's members I need to find the size of. I am specifically asking for the object's size without it's v-table considered. Also, I cannot modify it, so I cannot take advantage of this answer.

Is there a provision for this in C++, beyond summing a hard-coded sizeof for each member?

I am aware that v-tables are not mandated by C++. I am also aware that anything I do with this information will be widely considered "bad form". This question is simply asking if it's possible, not endorsing the behavior.


It has come to my attention that I need to clarify this question. 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: https://stackoverflow.com/a/31454039/2642059

The accepted answer does provide me the information I needed to do this. But, in-spite of behavior that I consider endemic to the worst of http://stackoverflow.com curiousguy points out a shortcoming of the accepted answer.

The extension from the accepted answer to multiple inheritance is patently obvious, but it is valid that the answer should include it. As a stopgap I've added a live example of how to deal with multiple inheritance: http://ideone.com/1QOrMz I will request that user2596732 updates his answer or I will add a supplementary answer to the question on how to deal with multiple inheritance.

3条回答
SAY GOODBYE
2楼-- · 2019-08-07 13:25

In order to discover the layout of a polymorphic object, you can compare pointers to member objects; the simple demonstration program "draws" the layout of an object with symbols:

  • a lowercase letter is the name of a data member
  • an uppercase letter is the name of a base class
  • * indicates part of the object that do not belong to any member subobject or base class subobject

There is a symbol for each byte (a char is a byte by definition).

The vptr(s) must be in the "empty" space, the space not allocated for data members.

Type definitions are:

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 { 
};

Output is:

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

See https://ideone.com/g5SZwk

Because we know the compiler is using vptrs, the locations of the vptrs are obvious in these "drawings".

About inheritance in C++

Non-virtual inheritance

When virtual inheritance is not used, the base class subobjects inheritance graph is always a tree rooted in the most derived class, even when the subtyping graph is not a tree:

struct Repeated {
    virtual void f();
    virtual void g();
};
struct Left : Repeated {
    void g();
};
struct Right : Repeated {
    void g();
};
struct Bottom : Left, Right {
    void f();
};

The subtyping graph is:

           Left
         /      \
Repeated          Bottom
         \      /
           Right

The subobject graph is:

Left::Repeated ---  Left
                         \
                          Bottom
                         /
Right::Repeated --- Right

This is crucial effect of non-virtual inheritance: the graphs don't always match. If you don't understand that you don't understand non-virtual inheritance!

This implies that conversions from Bottom* to Repeated* are ambiguous.

In this example:

  • Bottom::f() overrides both Left::Repeated::f() and Right::Repeated::f() at the same time.
  • Left::Repeated::g() is overridden by Left::g()
  • Right::Repeated::g() is overridden by Right::g()

Here the lookup of the name g in Bottom would fail with an ambiguity, so it would be an error to use an unqualified g in Bottom.

Virtual inheritance

When virtual inheritance is used, the base class subobjects inheritance is an acyclic directed graph with the most derived class as a unique terminal:

struct Unique { virtual void f(); };
struct Left : virtual Unique { void f(); };
struct Right : virtual Unique { void f(); };
struct Bottom : Left, Right { void f(); };

Here all other f() declarations override Unique::f().

Here the subobject graph matches the subtype graph:

           Left
         /      \
  Unique         Bottom
         \      /
           Right
查看更多
Viruses.
3楼-- · 2019-08-07 13:33

Nope.​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

查看更多
小情绪 Triste *
4楼-- · 2019-08-07 13:33

sizeof(Class) only includes a VTable pointer.

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() {
    };
};

So for this example,

    cout << sizeof(A)-sizeof(void*) << endl;
    cout << sizeof(B)-sizeof(void*) << endl;
    cout << sizeof(C)-sizeof(void*) << endl;

should give you the correct answer. 8 16 20

查看更多
登录 后发表回答