请教,c++虚继承,sizeof大小

ddweidong 2013-10-03 04:42:37
#include <iostream>

/*
* 带有数据成员的基类
*/
struct CBaseClass
{
CBaseClass( size_t i ) : m_val( i ) {}

size_t m_val;
};
/*
* 虚拟继承体系
*/
struct CSubClassV1 : public virtual CBaseClass
{
CSubClassV1( size_t i ) : CBaseClass( i ) {}
};

struct CSubClassV2 : public virtual CBaseClass
{
CSubClassV2( size_t i ) : CBaseClass( i ) {}
};
struct CSubClassV3 : public virtual CBaseClass
{
CSubClassV3( size_t i ) : CBaseClass( i ) {}
};
struct CDiamondClass1 : public CSubClassV1, public CSubClassV2
{
CDiamondClass1( size_t i ) : CBaseClass( i ), CSubClassV1( i ), CSubClassV2( i ) {}
};
struct CDiamondClass2 : public CSubClassV1, public CSubClassV2, public CSubClassV3
{
CDiamondClass2( size_t i ) : CBaseClass( i ), CSubClassV1( i ), CSubClassV2( i ), CSubClassV3(i) {}
};

struct CDiamondSubClass1 : public CDiamondClass1
{
CDiamondSubClass1( size_t i ) : CBaseClass( i ), CDiamondClass1( i ) {}
};
struct CDiamondSubClass2 : public CDiamondClass1, public CDiamondClass2
{
CDiamondSubClass2( size_t i ) : CBaseClass( i ), CDiamondClass1( i ), CDiamondClass2(i) {}
};

int main( int argc, char *argv[] )
{
/*
* 类体系中的尺寸.
*/
std::cout << "sizeof( CBaseClass1 ) = " << sizeof( CBaseClass ) << std::endl;
std::cout << std::endl;
std::cout << "sizeof( CSubClassV1 ) = " << sizeof( CSubClassV1 ) << std::endl;
std::cout << "sizeof( CSubClassV2 ) = " << sizeof( CSubClassV2 ) << std::endl;
std::cout << "sizeof( CDiamondClass1 ) = " << sizeof( CDiamondClass1 ) << std::endl;
std::cout << "sizeof( CDiamondClass2 ) = " << sizeof( CDiamondClass2 ) << std::endl;
std::cout << "sizeof( CDiamondSubClass1 ) = " << sizeof( CDiamondSubClass1 ) << std::endl;
std::cout << "sizeof( CDiamondSubClass2 ) = " << sizeof( CDiamondSubClass2 ) << std::endl;
std::cout << std::endl;

return 0;
}


环境:win7 64位, vs2010
下面图片是他们继承的层次示意图,红色的数字是运行的结果

我不明白的是 CDiamondClass1、CDiamondClass2、CDiamondSubClass1、CDiamondSubClass2这四个大小是怎么算的,请教各位。
...全文
188 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
taodm 2013-10-03
  • 打赏
  • 举报
回复
换一个编译器,你以为明白的东西,结论就完全可以不对了。
别多浪费精力讨论这的东西。
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
引用 8 楼 Adol1111 的回复:
内存布局什么的,光说是说不清楚的,还要牵扯对齐问题、虚函数表指针的位置等(这个看编译器实现)。还是直接用编译器打印看看比较清楚点。下面是用VS打印出来的:
class CBaseClass        size(8):
        +---
 0      | m_val
        +---

class CSubClassV1       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CSubClassV2       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CSubClassV3       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CDiamondClass1    size(24):
        +---
        | +--- (base class CSubClassV1)
 0      | | {vbptr}
        | +---
        | +--- (base class CSubClassV2)
 8      | | {vbptr}
        | +---
        +---
        +--- (virtual base CBaseClass)
16      | m_val
        +---

class CDiamondClass2    size(32):
        +---
        | +--- (base class CSubClassV1)
 0      | | {vbptr}
        | +---
        | +--- (base class CSubClassV2)
 8      | | {vbptr}
        | +---
        | +--- (base class CSubClassV3)
16      | | {vbptr}
        | +---
        +---
        +--- (virtual base CBaseClass)
24      | m_val
        +---

class CDiamondSubClass1 size(24):
        +---
        | +--- (base class CDiamondClass1)
        | | +--- (base class CSubClassV1)
 0      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
 8      | | | {vbptr}
        | | +---
        | +---
        +---
        +--- (virtual base CBaseClass)
16      | m_val
        +---

class CDiamondSubClass2 size(48):
        +---
        | +--- (base class CDiamondClass1)
        | | +--- (base class CSubClassV1)
 0      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
 8      | | | {vbptr}
        | | +---
        | +---
        | +--- (base class CDiamondClass2)
        | | +--- (base class CSubClassV1)
16      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
24      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV3)
32      | | | {vbptr}
        | | +---
        | +---
        +---
        +--- (virtual base CBaseClass)
40      | m_val
        +---
我的编译器是8字节对齐的,你的可能是4字节对齐,所以有差异,这里仅供参考。
谢谢,这个直观多了,比用一个指针去遍历这些成员函数数据成员的容易理解多了。 ps.我的机器也是4字节对齐的,所以上面结果是对的,总算弄明白了
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
引用 7 楼 ddweidong 的回复:
[quote=引用 6 楼 ddweidong 的回复:] [quote=引用 4 楼 jerry_dqh 的回复:] 楼主这种不是最复杂的,能理解CSubClassV1,V2,V3为啥为8,其他均可以理解了。V1主要要多一个存储指向子类的指针,当然微软可能不是用指针,可能用偏移量表示,但是均要占用4字节。所以V1为8。大概都是这个道理 CDiamondSubClass2 这个Size为24,主要是下面的布局 | p1 | p2 | p3 |p4 | p5 | 0x7| | <--CDiamondClass1----->|<----CDiamondClass2---->| m_val | p1,p2,p3,p4,p5均是指向m_val的偏移量,或者其他的信息。就是能通过p1找到m_val 楼主可以直接用VC将变量CDiamondSubClass2变量的开始6个4byte大小的内存打出来就知道了。 最好还是看一下深度探索c++对象模型 这本书。
就是说它自己保存了他基类的虚函数指针对吧,刚才看了一个博客他也是这么说的http://blog.csdn.net/haoel/article/details/1948051[/quote] 但是如果是刚才说的那样,那最后CDiamonSubClass1和2的大小有不对了,也不符合内存对齐的情况呀?[/quote] 终于搞明白了,你说的是对的,看了刚才那两篇博客高明白了这个问题了谢谢了
Adol1111 2013-10-03
  • 打赏
  • 举报
回复
内存布局什么的,光说是说不清楚的,还要牵扯对齐问题、虚函数表指针的位置等(这个看编译器实现)。还是直接用编译器打印看看比较清楚点。下面是用VS打印出来的:
class CBaseClass        size(8):
        +---
 0      | m_val
        +---

class CSubClassV1       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CSubClassV2       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CSubClassV3       size(16):
        +---
 0      | {vbptr}
        +---
        +--- (virtual base CBaseClass)
 8      | m_val
        +---

class CDiamondClass1    size(24):
        +---
        | +--- (base class CSubClassV1)
 0      | | {vbptr}
        | +---
        | +--- (base class CSubClassV2)
 8      | | {vbptr}
        | +---
        +---
        +--- (virtual base CBaseClass)
16      | m_val
        +---

class CDiamondClass2    size(32):
        +---
        | +--- (base class CSubClassV1)
 0      | | {vbptr}
        | +---
        | +--- (base class CSubClassV2)
 8      | | {vbptr}
        | +---
        | +--- (base class CSubClassV3)
16      | | {vbptr}
        | +---
        +---
        +--- (virtual base CBaseClass)
24      | m_val
        +---

class CDiamondSubClass1 size(24):
        +---
        | +--- (base class CDiamondClass1)
        | | +--- (base class CSubClassV1)
 0      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
 8      | | | {vbptr}
        | | +---
        | +---
        +---
        +--- (virtual base CBaseClass)
16      | m_val
        +---

class CDiamondSubClass2 size(48):
        +---
        | +--- (base class CDiamondClass1)
        | | +--- (base class CSubClassV1)
 0      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
 8      | | | {vbptr}
        | | +---
        | +---
        | +--- (base class CDiamondClass2)
        | | +--- (base class CSubClassV1)
16      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV2)
24      | | | {vbptr}
        | | +---
        | | +--- (base class CSubClassV3)
32      | | | {vbptr}
        | | +---
        | +---
        +---
        +--- (virtual base CBaseClass)
40      | m_val
        +---
我的编译器是8字节对齐的,你的可能是4字节对齐,所以有差异,这里仅供参考。
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
引用 6 楼 ddweidong 的回复:
[quote=引用 4 楼 jerry_dqh 的回复:] 楼主这种不是最复杂的,能理解CSubClassV1,V2,V3为啥为8,其他均可以理解了。V1主要要多一个存储指向子类的指针,当然微软可能不是用指针,可能用偏移量表示,但是均要占用4字节。所以V1为8。大概都是这个道理 CDiamondSubClass2 这个Size为24,主要是下面的布局 | p1 | p2 | p3 |p4 | p5 | 0x7| | <--CDiamondClass1----->|<----CDiamondClass2---->| m_val | p1,p2,p3,p4,p5均是指向m_val的偏移量,或者其他的信息。就是能通过p1找到m_val 楼主可以直接用VC将变量CDiamondSubClass2变量的开始6个4byte大小的内存打出来就知道了。 最好还是看一下深度探索c++对象模型 这本书。
就是说它自己保存了他基类的虚函数指针对吧,刚才看了一个博客他也是这么说的http://blog.csdn.net/haoel/article/details/1948051[/quote] 但是如果是刚才说的那样,那最后CDiamonSubClass1和2的大小有不对了,也不符合内存对齐的情况呀?
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
引用 4 楼 jerry_dqh 的回复:
楼主这种不是最复杂的,能理解CSubClassV1,V2,V3为啥为8,其他均可以理解了。V1主要要多一个存储指向子类的指针,当然微软可能不是用指针,可能用偏移量表示,但是均要占用4字节。所以V1为8。大概都是这个道理 CDiamondSubClass2 这个Size为24,主要是下面的布局 | p1 | p2 | p3 |p4 | p5 | 0x7| | <--CDiamondClass1----->|<----CDiamondClass2---->| m_val | p1,p2,p3,p4,p5均是指向m_val的偏移量,或者其他的信息。就是能通过p1找到m_val 楼主可以直接用VC将变量CDiamondSubClass2变量的开始6个4byte大小的内存打出来就知道了。 最好还是看一下深度探索c++对象模型 这本书。
就是说它自己保存了他基类的虚函数指针对吧,刚才看了一个博客他也是这么说的http://blog.csdn.net/haoel/article/details/1948051
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
引用 3 楼 bichenggui 的回复:
CDiamondClass1 的大小等于一个size_t 再加上2个指向基类的指针。具体可参考虚基类的实现。大致是这么个道理。
那CDiamonSubClass1呢,一个size_t加一个指向基类的指针?貌似不是的.....
碼上道 2013-10-03
  • 打赏
  • 举报
回复
楼主这种不是最复杂的,能理解CSubClassV1,V2,V3为啥为8,其他均可以理解了。V1主要要多一个存储指向子类的指针,当然微软可能不是用指针,可能用偏移量表示,但是均要占用4字节。所以V1为8。大概都是这个道理 CDiamondSubClass2 这个Size为24,主要是下面的布局 | p1 | p2 | p3 |p4 | p5 | 0x7| | <--CDiamondClass1----->|<----CDiamondClass2---->| m_val | p1,p2,p3,p4,p5均是指向m_val的偏移量,或者其他的信息。就是能通过p1找到m_val 楼主可以直接用VC将变量CDiamondSubClass2变量的开始6个4byte大小的内存打出来就知道了。 最好还是看一下深度探索c++对象模型 这本书。
必成桂 2013-10-03
  • 打赏
  • 举报
回复
CDiamondClass1 的大小等于一个size_t 再加上2个指向基类的指针。具体可参考虚基类的实现。大致是这么个道理。
ddweidong 2013-10-03
  • 打赏
  • 举报
回复
我在请教....等待牛逼的人
qq120848369 2013-10-03
  • 打赏
  • 举报
回复
楼主牛逼。。。

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧