我们知道,c++ 中的多态,绝大多数的编译器都是通过虚表来实现的。
那么,我们是不是应该去探究下,编译器是怎样去管理的呢?
那么,好的,我们就通过代码来满足我们的好奇心吧。
首先,我们一步一步的来探究吧:
先来点简单的吧:(这里我默认大家对指针的使用很熟练的)
注意咯:我这里并没有为类添加成员,这是一个不足的地方,大家可以再看完之后,自己添加上去。
因为我这里主要是讨论虚表的问题,所以就偷了个懒。
好了,进入正题咯
一、单继承下的类图:(存在虚函数的覆盖)
Derived的内存是怎样分布的呢?虚函数是怎样存放在虚表中的呢?
-
我先把得出的结果以图形的方式描述出来,两个图放在一起更好的比较咯。
来看下我的代码吧:
是不是被这代码吓到了。不急我慢慢的来解析下:
类图的实现就不用我多说了吧。这个都看不懂的话,请移步。
void (*Func)()://定义一个函数指针,这个函数指针的返回值是void,参数是void.(我为什么这么做呢?因为我类中定义的函数就是这种类型的,后面有大用处呢。)
上面的理解了,那下面的这个不就很简单咯。
typedef void (*Func)();//将Func 作为一种数据类型,这个数据类型是返回值为void,参数是void 的函数指针
Base* b = new Derived;
Func fn = NULL;//声明一个变量咯,这个变量的类型是返回值为void,参数是void 的函数指针
fn = (Func)(*((int*)(*(int*)b)+0));//这个看的是不是很晕,好吧我这个复杂,就得用图形来解释咯。
还有,你是不是很奇怪,我为什么能够知道那么写?
首先,通过书本我知道,存在虚函数的对象,编译器都会去维护虚表。那我就想啊,这虚表时怎样存放虚函数的,还有指向续表的指针在对象的内存的那个位置。
然后就是不断的尝试咯。发现了其中的本质。当我tmp不断的往下指是,存放的函数一个一个的被调用出来了,到最后悔出现一个段错误,说明,后面的内存我不能在使用了。
所以就得出了如上的图形描述。
根据以上的代码,我们运行出的结果:
这样我们不就得出了Derived的虚表时怎样存放虚函数的了。
写完了,咱就得去总结下吧:
①在单继承存在虚函数的覆盖时,子类的对象只有一张虚表,子类对象的第一个索引指向的是虚表,虚表中存放虚函数的顺序是,先存放父类的虚函数,如果存在着子类覆盖
父类的虚函数,则父类的这个虚函数被覆盖。还有一点是,续表中存放的是栈中函数的地址。
看完第一个,咱是不是应该有点问题呢?难道只有一张虚表?多重继承下虚表又是怎样的呢?多重虚继承又是怎样的呢?多重继承抽象类呢?多重虚继承抽象类呢?
晕,好麻烦啊。咱就先把上面的看懂了。下一节再来吧。有什么不足之处欢迎大家的批评指出。
有什么问题或错误可以留言或Email:chenshan0821@sina.com
祝大家生活愉快。。。。。