获取对象的成员的sizeof [英] Get the sizeof Object's Members

查看:211
本文介绍了获取对象的成员的sizeof的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个对象谁是成员我需要找到的大小。我特别要求的对象的大小没有它的v表考虑。此外,我无法修改它,因此我无法利用此答案



除了为每个成员加上硬编码的 sizeof ,在C ++中是否有这样的规定?



我知道v表不是由C ++强制。我也知道,我对这些信息做的任何事情都会被广泛认为是坏的形式。






这让我注意到了我需要澄清此问题。我想用这个问题学习的是如何把一个父母给孩子。也就是说,我想保留子级的v表,但复制父级的成员变量: http://stackoverflow.com/a/ 31454039/2642059



接受的答案 为我提供了我需要的信息。但是,尽管我认为流行的最糟糕的行为, http://stackoverflow.com curiousguy 指出了接受的答案



从接受的答案到多重继承的扩展很明显,但答案应该包括它是有效的。作为一个临时我添加了一个如何处理多重继承的实例: http://ideone.com/1QOrMz我将要求 user2596732 更新他的答案,否则我将在如何处理多个问题的问题上添加补充答案继承。

解决方案

为了发现多态对象的布局,可以比较指向成员对象的指针;简单的演示程序用符号绘制对象的布局:




  • 小写字母是数据成员的名称

  • 大写字母是基类的名称

  • * 表示对象的一部分不属于任何成员子对象或基类子对象



每个字节都有一个符号( 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在偏移4
T的布局是
*** * iiii
sizeof U是12
sizeof U :: l是8
l是在偏移4
U的布局是
**** llllllll
sizeof Der is 20
Der :: i在偏移量4
Der :: l在偏移量12
Der :: T在偏移量0
Der :: U在偏移8
Der的布局是
TTTTiiiiUUUUllllllll
sizeof Der2是20
Der2 :: i在偏移16
Der2 :: l在偏移4
Der2 :: T在偏移量12
Der2 :: U位于偏移量0
Der2的布局是
UUUUllllllllTTTTiiii
Der3的sizeof是24
Der3 :: i位于偏移量8
Der3 :: l位于偏移量16
Der3 :: T位于偏移量4
Der3 :: U位于偏移量12
Der3的布局为
**** TTTTiiiiUUUUllllllll

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



因为我们知道编译器使用vptrs,vptrs的位置



关于C ++中的继承



非虚拟继承



当不使用虚拟继承时,即使当子类型图不是树时,基类subobjects继承图总是一个以最大派生类为根的树:

  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 --- Left 
\
Bottom
/
Right :: Repeated --- Right

这是非虚拟继承的关键效果:图形并不总是匹配。如果你不明白你不明白非虚拟继承!



这意味着从 Bottom * 重复的* 是不明确的。



在此示例中:




  • Bottom :: f()覆盖 Left :: Repeated :: f code>和 Right :: Repeated :: f()

  • Left :: Repeated :: g() Left :: g()覆盖

  • code> Right :: Repeated :: g()被覆盖 Right :: g()



此处查找 Bottom g >会失败并带有歧义,因此在 Bottom 中使用不合格 g >

虚继承



当使用虚拟继承时,基类subobjects继承是一个非循环有向图,作为唯一终端:

  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()



这里子对象图匹配子类型图:

 
/ \
唯一底
\ /


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: http://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.

解决方案

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

这篇关于获取对象的成员的sizeof的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆