免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: donet8

C++对象模型一个问题: sizeof得到的大小和我想象的不一样! [复制链接]

论坛徽章:
0
发表于 2012-03-09 17:03 |显示全部楼层
谢谢你的耐心解释:

(1)"多重继承的条件下,一个 vptr 行不行呢?"这句话以上的内容我都懂,大家都懂
这个基础我还是有的,呵呵

(2)但我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。
放在一个表里面,用一个vptr去指,会有什么问题么?

还请继续指点!

论坛徽章:
0
发表于 2012-03-09 17:07 |显示全部楼层
(3)我知道VC2005/2010支持编译选项/d1reportAllClassLayout ,可以dump出来所有的类的内存模型。
(4)我知道"占地方的不是函数指针,是虚函数表指针"
问题是,既然s4和s5有两个虚表指针,分别指向s1的虚表和s2的虚表,那么我用模拟的办法应该可以访问到这两个虚表。
    所以,我写了一段测试程序。测试程序可以得到s1,s2,s3的虚表的地址,但是对于s4和s5,只能得到第一个虚表的位置,而得不到第二个虚表的位置。这是为什么呢?下面这段测试代码,运行结果如下:
4,4,4,8,8

s1 vtble address=00416964
s2 vtble address=00416954
s3 vtble address=004169A4
s4 vtble address1=00416A94
s4 vtble address2=CCCCCCCC   //是不是应该指向s4::s2的虚表,不应该是CCCCCCCC
s5 vtble address1=004169B0
s5 vtble address2=CCCCCCCC   //是不是应该指向s5::s2的虚表,不应该是CCCCCCCC
Press any key to continue . . .

  1. #include "stdafx.h"
  2. #include <string>
  3. using namespace std;
  4. struct s1{
  5.     virtual void f(){};
  6. }o1;
  7. struct s2{
  8.     virtual void g(){};
  9. }o2;
  10. struct s3: public s1{
  11.     virtual void x(){};
  12. }o3;
  13. struct s4: public s1,s2{
  14. }o4;
  15. struct s5: public s1,s2{
  16.     virtual void y(){};
  17. }o5;
  18. int  main( void){
  19.      printf("%d,%d,%d,%d,%d\n\n",sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4),sizeof(s5));
  20.      typedef void(*virtual_function)(void);
  21.      struct s123_equivalence{
  22.          virtual_function* pVtbl;
  23.      }o123;
  24.      memcpy(&o123,&o1,sizeof(s3));
  25.      printf("s1 vtble address=%p\n",o123.pVtbl);
  26.      memcpy(&o123,&o2,sizeof(s3));
  27.      printf("s2 vtble address=%p\n",o123.pVtbl);
  28.      memcpy(&o123,&o3,sizeof(s3));
  29.      printf("s3 vtble address=%p\n",o123.pVtbl);

  30.      struct s45_equivalence{
  31.          virtual_function* pV1;
  32.          virtual_function* pV2;
  33.      }o45;
  34.      memcpy(&o45,&o4,sizeof(s3));
  35.      printf("s4 vtble address1=%p\n",o45.pV1);
  36.      printf("s4 vtble address2=%p\n",o45.pV2);

  37.      memcpy(&o45,&o5,sizeof(s3));
  38.      printf("s5 vtble address1=%p\n",o45.pV1);
  39.      printf("s5 vtble address2=%p\n",o45.pV2);

  40.      return 0;
  41. }
复制代码

论坛徽章:
0
发表于 2012-03-09 17:26 |显示全部楼层
回复 11# donet8


    35行 和 39行 代码有误,应该是 sizeof(s4) 和 sizeof(s5)

论坛徽章:
0
发表于 2012-03-09 17:38 |显示全部楼层
可能两个虚表不是像结构体o45那样顺序存储的吧,我猜的

论坛徽章:
0
发表于 2012-03-09 17:41 |显示全部楼层
mind09 发表于 2012-03-09 17:38
可能两个虚表不是像结构体o45那样顺序存储的吧,我猜的


那段代码有误,修改后,就可以得到2个虚表指针的正确值了。

论坛徽章:
0
发表于 2012-03-09 17:48 |显示全部楼层
本帖最后由 lsupper 于 2012-03-09 17:49 编辑

回复 10# donet8

针对问题2:
(2)但我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。
放在一个表里面,用一个vptr去指,会有什么问题么?

虽然不同名,但是当子类要转换为基类进行操作的时候,就会出现问题。
比如你有个子类C,继承自A,B,你想做如下操作的时候:
A *ac = (A*)(new C);
B *bc = (B*)(new C);

这个时候怎么办呢?f,g函数如果要放到一张虚表里面,谁先谁后呢?ac,bc怎么能很快的找到各自原来的虚函数呢?进而实现调用呢?
所以必须保持至少两张虚表各自存储A,B对应的虚函数地址。而子类C中自有的虚函数,就放到相对两张虚表后面...这样就完美了...
LZ,进而你可以想象下如果,A,B都继承自D呢?
   

论坛徽章:
0
发表于 2012-03-09 18:11 |显示全部楼层
bufferfly 发表于 2012-03-09 17:40
回复 10# donet8

仔细看我在9楼的帖子,编译器必须在对象构造的时候就给 vptr 赋值。等到虚函数调用的时 ...


泉水般清晰的解释。
给分!

论坛徽章:
0
发表于 2012-03-09 18:28 |显示全部楼层
回复 17# donet8

嘻嘻,共同学习。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP