上一节,我们讲到了虚函数,那么你知道虚函数是如何做到多态的吗?

虚函数是通过后期绑定,在执行时间接通过一张虚函数表,间接调用欲绑定的函数。表中的每一个元素都指向虚函数的地址。当然,编译器也会为类增加一项成员变量,此成员变量是一个指向虚函数表的指针。可用图解表示如下:

 

注意:

成员函数memfuc()经过编译之后,形成代码,然后放在内存中的代码区,并不是数据段。成员函数都是放在一起,而且由同一个类的所有对象共享。,用sizeof(a)计算的结果是不包括代码段的。

以下几点,等下我们一一论证:

1.每一个由此类派生出来的对象,都有一个vptr。当我们通过对象调用虚函数时,实际上是通过vptr找到虚函数表,然后通过虚函数表找到真正的虚函数地址。

2.虚函数表中的内容是根据类中的虚函数声明顺序一个一个填 入函数指针。

3.当派生类继承了基类后,同时也继承了虚函数表,当我们在派生类中修改了虚函数时,其对应的虚函数表中所指向的函数地址,就不再是基类的了,而是派生类的了。此点我们用图解如下:

 

现在我们来分析一下到底是不是这样的?这一节讲解以下面的代码为例(在上一节的例子基础上修改而成)

 

Code

运行后的结果如下:

 

我们来分析一下:

1.sizeof(CEmployee)的大小为8,而这个类中只有一个整型是4个字节,那么还有四个字节是谁占了呢,对了,就是指向虚函数表的vptr成员变量。说明确实在类中只要有虚函数,就一定会有vptr这个成员变量。

2.sizeof(CWage)的大小为16,实际上是基类的整型+本类的两个整型+从基类继承的vptr也占用了四个字节,刚好说明派生类继承了虚函数表。

3.看清0x0012ff68这个内存地址,它是类CWage对象的起始地址,这个地址中的内容刚好是vptr,我们跟踪程序,调试时可查,我把图取上来大家看一下:

 

4.虚函数表中的内容是根据类中的虚函数声明顺序一个一个填 入函数指针。大家看上图先是压入CWag::computerPay,然后再是CWage::display。

5.当派生类继承了基类后,同时也继承了虚函数表,当我们在派生类中修改了虚函数时,其对应的虚函数表中所指向的函数地址,就不再是基类的了,而是派生类的了。现在我们看到的是b对象(即CWage),转到C对象时,会发现虚函数表中的地址都发生变化了。

今天就先写到这儿,本人才shu学浅,有什么意见或见意,希望能与大家一同探讨。

 

 

 

 

posted on 2009-02-20 01:03  jasonM  阅读(344)  评论(0编辑  收藏  举报