虚函数表的空间问题

cnvb 2007-08-26 12:27:53
小弟写一简单的测试程序如下,主要目的是测试当类中有虚函数存在时的内存分配情况:
#include <iostream.h>

class test
{
public:
virtual void print()
{
cout << "Print from test" << endl;
}

};

class test2:public test
{
public:
virtual void pp()
{
cout << "PP from test2" << endl;
}

virtual void print()
{
cout << "Print from test2" << endl;
}

};

class test3:public test2
{
public:
virtual void pp()
{
cout << "PP from test3" << endl;
}

virtual void print()
{
cout << "Print from test3" << endl;
}
};


void main()
{
test *pt,t;
test2 *ptt,tt;
test3 *pttt,ttt;
cout << "Size of t = " << sizeof(t) << endl;
cout << "Size of tt = " << sizeof(tt) << endl;
cout << "Size of ttt = " << sizeof(ttt) << endl;
tt.pp()
ttt.pp();
t.print();
tt.print();
ttt.print();
pt = &tt;
ptt = &ttt;
pttt = &ttt;
pt->print();
ptt->print();
pttt->print();
ptt->pp();
pttt->pp();
}

它的显示结果为:

Size of t = 4
Size of tt = 4
Size of ttt = 4
PP from test2
PP from test3
Print from test
Print from test2
Print from test3
Print from test2
Print from test3
Print from test3
PP from test3
PP from test3

我们知道,当类中存在虚函数里.则编译器会在编译期自动的给该类生成一个函数表.并在所有该类的对像中放入一个隐式变量如_vfprt,该变量是一个指针变量,它的值指向那个类中的由编译器生成的虚函数表.
在调试的状态下.小弟查看调试器中的内存状态.发现.如test的子类test2的对像tt中只有指针变量_vfptr存在,该变量所指向的类test的虚函数表中只有类test2的print()函数的地址.这里并没有子类中的虚函数pp()的地址,小弟认为这应该就是为什么"指向子类的父类的引用或指针不能访问父类中并不存在的函数或成员"的规则限制.
但有趣的是.既然在虚表中不存在虚函数pp()的地址.那最少子类也应该生成一个类似的表以存放那些在父类中不存的虚函数吧.这样也符合"当类中有虚函数里编译器会自动为该类生成虚函数表,并在所有该类对像中插入一个指向该表的指针."的规则啊...但从调试器的角度来看,好像什么都没有...没有新的虚函数表生成,也没有看到pp()函数的存在.
这样问题就产生了.看我的测试显示的结果,显然.在子类的子类test3中多态的性质还是被应用了出来(如pp()函数的调用).
这不是很奇怪,test3的父类的虚表中并不存在pp()的地址.那么在其子类test3中的多态又是怎么实现的呢?
敬请各位大大不吝指教......
...全文
204 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
cnvb 2007-08-26
  • 打赏
  • 举报
回复
那几条内存变量的sizeof()语句已经说明了.在子类中只有那个被插入的隐含变量_vfptr的存在...而并没有生成其它的任何内容...类test2的虚函数pp()即不存在于虚函数表.又不存在于类对像中...那么到底它被存放在哪里?它又是怎样实现多太的性质的???
liwenso 2007-08-26
  • 打赏
  • 举报
回复
小弟不才

程序和结果都没有问题.觉得应该是与编译器有关吧.猜测^^
cnvb 2007-08-26
  • 打赏
  • 举报
回复
结分了...才20分让老大们回答这么多问题有点对不住啊...呵呵...
cnvb 2007-08-26
  • 打赏
  • 举报
回复
>>虚函数可以被动态或者静态邦定。tt.test::print()是由编译器静态绑定的,和虚表没有关系。


嗯,静态绑定,应该是这样...这一点小弟真的是没想到...还在朝动态方面想呢...

对于问题2,我是看深入c++对像模型的书才有此一问的...总感觉有点对不上号...
iambic 2007-08-26
  • 打赏
  • 举报
回复
>>但如果我添加这样的语句:tt.test::print()...而它的显示结果为 print from test..
>>显然.在test2子类中正确的找到了被子类重写过的父类的函数print()...

虚函数可以被动态或者静态邦定。tt.test::print()是由编译器静态绑定的,和虚表没有关系。
cnvb 2007-08-26
  • 打赏
  • 举报
回复
当如果真如iambic()兄所说的那样是因为调试器的原因...那么新的问题出来了...

因为子类继承了父类的虚函数的特性,在子类中的虚函数的地址会改写已被重写过的虚表中的函数地址(如test2类的print()函数).但其并没有生成新的指向子类虚表的指针(事实上真的没有生成.看sizeof语句的输入就知道了)...

但如果我添加这样的语句:tt.test::print()...而它的显示结果为 print from test..

显然.在test2子类中正确的找到了被子类重写过的父类的函数print()...但事实上在子类的对像中该函数的地址是被test2重写过的...那么它又是如何找到真正的test的函数地址的呢?---问题1

如果没有生成新的指向子类的虚函数的地址.那么当在多重继承的时候...子类的虚函数又该如何存放???---问题2

请各位大大踊跃回答啊...
cnvb 2007-08-26
  • 打赏
  • 举报
回复
谢谢iambic()兄的回答...

如果真是调试器的原因,那就糗大了...
iambic 2007-08-26
  • 打赏
  • 举报
回复
你用的是VC6吧,调试窗口没显示出来罢了。因为虚表指针是test对象模型的一部分,所以虚表只显示了两个。实际上后面还有的。
cnvb 2007-08-26
  • 打赏
  • 举报
回复
回楼上的iambic()兄....

那个虚表里只有print()并没有pp()的地址...这个我检查过了....你也可以测试一下...
iambic 2007-08-26
  • 打赏
  • 举报
回复
test2的虚表中,pp的值可能在print后面,楼主检查过没有?
iambic 2007-08-26
  • 打赏
  • 举报
回复
test2的_vfptr中,pp的值可能在print后面,楼主检查过没有?

64,637

社区成员

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

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