多继承情况下,虚表指针的一个有关问题
多继承情况下,虚表指针的一个问题
我知道:
1. 有虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放着虚函数的地址
2. 有虚函数的类对象保存着一个指向虚表的指针
3. 父类和子类共享虚表指针
4. 多重继承增加额外的指针
5. 就算一个class有再多的虚函数,sizeof()大小也不会变
6. 一个class再多加一个父类,会多增加一个虚表指针
7. 我知道VC2005/2010支持编译选项/d1reportAllClassLayout ,可以dump出来所有的类的内存模型。
8. 我知道"占地方的不是函数指针,是虚函数表指针"
我也知道:
假设 Derived 除了 Base外,还继承 Base2,并且 Base2 中有两个虚函数 x() 和 y (),那么 Derived 对象的存储结构也许是这样的(只是大概,和具体编译器相关)。
Derived: VTable_D:
----------- --------------
| vptr | | f() 入口 |
+---------+ +----------+
| Base的 | | g() 入口 |
| 数据 | -------------
+---------+
| vptr2 | VTable_D2:
+---------+ -------------
| Base2的 | | x() 入口 |
| 数据 | +-----------+
+---------+ | y() 入口 |
| Derived的| -------------
| 数据 |
------------
**************************************************************
问题是:
多重继承的条件下,一个 vptr 行不行呢? 我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。放在一个表里面,用一个vptr去指,会有什么问题么?
我写了一段测试程序。测试程序可以得到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
求高手解释!!!@!!
源代码如下:
**************************************************************
------解决方案--------------------
多重继承的条件下,一个 vptr 行不行呢? 我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。放在一个表里面,用一个vptr去指,会有什么问题么?
你怎么维护子对象的完整性呢?
------解决方案--------------------
我知道:
1. 有虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放着虚函数的地址
2. 有虚函数的类对象保存着一个指向虚表的指针
3. 父类和子类共享虚表指针
4. 多重继承增加额外的指针
5. 就算一个class有再多的虚函数,sizeof()大小也不会变
6. 一个class再多加一个父类,会多增加一个虚表指针
7. 我知道VC2005/2010支持编译选项/d1reportAllClassLayout ,可以dump出来所有的类的内存模型。
8. 我知道"占地方的不是函数指针,是虚函数表指针"
---------------------------------
这是你所理解的?
3,4,6是有问题的
何为共享虚表指针?虚表是和类相关的,派生类的虚表是派生类的,基类的是基类的
为什么要增加额外的指针呢?除了虚继承会增加额外的指针外,虚表指针是永远只有一个的而不管基类有多少个
同上,和基类个数没有关系。
------解决方案--------------------
------解决方案--------------------
N个父类就有N虚表指针。
不共享虚表
4lshuodfdfd
------解决方案--------------------
代码写的有点小问题! 已经修改如下,这样应该就是你想要的结果吧!另外查看变量地址不需要这么复杂,直接调试看多方便!效果如图:
我知道:
1. 有虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放着虚函数的地址
2. 有虚函数的类对象保存着一个指向虚表的指针
3. 父类和子类共享虚表指针
4. 多重继承增加额外的指针
5. 就算一个class有再多的虚函数,sizeof()大小也不会变
6. 一个class再多加一个父类,会多增加一个虚表指针
7. 我知道VC2005/2010支持编译选项/d1reportAllClassLayout ,可以dump出来所有的类的内存模型。
8. 我知道"占地方的不是函数指针,是虚函数表指针"
我也知道:
假设 Derived 除了 Base外,还继承 Base2,并且 Base2 中有两个虚函数 x() 和 y (),那么 Derived 对象的存储结构也许是这样的(只是大概,和具体编译器相关)。
Derived: VTable_D:
----------- --------------
| vptr | | f() 入口 |
+---------+ +----------+
| Base的 | | g() 入口 |
| 数据 | -------------
+---------+
| vptr2 | VTable_D2:
+---------+ -------------
| Base2的 | | x() 入口 |
| 数据 | +-----------+
+---------+ | y() 入口 |
| Derived的| -------------
| 数据 |
------------
**************************************************************
问题是:
多重继承的条件下,一个 vptr 行不行呢? 我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。放在一个表里面,用一个vptr去指,会有什么问题么?
我写了一段测试程序。测试程序可以得到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
求高手解释!!!@!!
源代码如下:
**************************************************************
- C/C++ code
#include "stdafx.h" #include <string> using namespace std; struct s1{ virtual void f(){}; }o1; struct s2{ virtual void g(){}; }o2; struct s3: public s1{ virtual void x(){}; }o3; struct s4: public s1,s2{ }o4; struct s5: public s1,s2{ virtual void y(){}; }o5; int main( void){ printf("%d,%d,%d,%d,%d\n\n",sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4),sizeof(s5)); typedef void(*virtual_function)(void); struct s123_equivalence{ virtual_function* pVtbl; }o123; memcpy(&o123,&o1,sizeof(s3)); printf("s1 vtble address=%p\n",o123.pVtbl); memcpy(&o123,&o2,sizeof(s3)); printf("s2 vtble address=%p\n",o123.pVtbl); memcpy(&o123,&o3,sizeof(s3)); printf("s3 vtble address=%p\n",o123.pVtbl); struct s45_equivalence{ virtual_function* pV1; virtual_function* pV2; }o45; memcpy(&o45,&o4,sizeof(s3)); printf("s4 vtble address1=%p\n",o45.pV1); printf("s4 vtble address2=%p\n",o45.pV2); memcpy(&o45,&o5,sizeof(s3)); printf("s5 vtble address1=%p\n",o45.pV1); printf("s5 vtble address2=%p\n",o45.pV2); return 0; }
------解决方案--------------------
多重继承的条件下,一个 vptr 行不行呢? 我没有看出来“所以这些虚函数入口是不能放在同一个虚表当中的”怎么就不行了。f,g和x,y并不同名啊。放在一个表里面,用一个vptr去指,会有什么问题么?
你怎么维护子对象的完整性呢?
------解决方案--------------------
我知道:
1. 有虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放着虚函数的地址
2. 有虚函数的类对象保存着一个指向虚表的指针
3. 父类和子类共享虚表指针
4. 多重继承增加额外的指针
5. 就算一个class有再多的虚函数,sizeof()大小也不会变
6. 一个class再多加一个父类,会多增加一个虚表指针
7. 我知道VC2005/2010支持编译选项/d1reportAllClassLayout ,可以dump出来所有的类的内存模型。
8. 我知道"占地方的不是函数指针,是虚函数表指针"
---------------------------------
这是你所理解的?
3,4,6是有问题的
何为共享虚表指针?虚表是和类相关的,派生类的虚表是派生类的,基类的是基类的
为什么要增加额外的指针呢?除了虚继承会增加额外的指针外,虚表指针是永远只有一个的而不管基类有多少个
同上,和基类个数没有关系。
------解决方案--------------------
------解决方案--------------------
N个父类就有N虚表指针。
不共享虚表
4lshuodfdfd
------解决方案--------------------
代码写的有点小问题! 已经修改如下,这样应该就是你想要的结果吧!另外查看变量地址不需要这么复杂,直接调试看多方便!效果如图:
- C/C++ code
#include "stdafx.h" #include <string> using namespace std; struct s1{ virtual void f(){}; }o1; struct s2{ virtual void g(){}; }o2; struct s3: public s1{ virtual void x(){}; }o3; struct s4: public s1,s2{ }o4; struct s5: public s1,s2{ virtual void y(){}; }o5; int main( void){ printf("%d,%d,%d,%d,%d\n\n",sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4),sizeof(s5)); typedef void(*virtual_function)(void); struct s123_equivalence{ virtual_function* pVtbl; }o123; memcpy(&o123,&o1,sizeof(s3)); printf("s1 vtble address=%p\n",*(int *)o123.pVtbl); // 此处有问题! memcpy(&o123,&o2,sizeof(s3)); printf("s2 vtble address=%p\n",*(int *)o123.pVtbl); memcpy(&o123,&o3,sizeof(s3)); printf("s3 vtble address=%p\n",*(int *)o123.pVtbl); struct s45_equivalence{ virtual_function* pV1; virtual_function* pV2; }o45; memcpy(&o45,&o4,sizeof(o4)); // 有问题 修改为s4 printf("s4 vtble address1=%p\n",*(int *)o45.pV1); printf("s4 vtble address2=%p\n",*(int *)o45.pV2); memcpy(&o45,&o5,sizeof(o5)); // 有问题 修改为s5 printf("s5 vtble address1=%p\n",*(int *)o45.pV1); printf("s5 vtble address2=%p\n",*(int *)o45.pV2); return 0; }