C++语言程序设计

从这个表中可以看到，派生类中和基类都有的虚函数，在各自的VTABLE表中位置必须一样，如果派生类中没有重定义该虚函数，则它就使用基类的虚函数地址。派生类自己定义虚函数依次添加在VTABLE表中。
当编译器对类的定义进行编译时，如果类中含有虚函数，它就采用动态联编机制，生成这样一个VTABLE表，记录这个类的虚函数的地址。编译器在类的构造函数开头部分秘密添加了一段代码（如果用户没有显式定义构造函数，编译器会生成缺省构造函数），这段代码对用户是不可见的，它的作用是：初始化VPTR，使它指向该类的VTABLE。这样，当生成该类对象时，所做的第一件事就是将VPTR赋值，使它指向对应的VTABLE表。
现在有了VTALBE表，生成了该类对象，并已经设置了VPTR，使它指向VTABLE，那么当使用基类指针调用虚函数时，到底是怎么实现的呢？
对于上面的基类B和派生类C，我们看下面的程序段：
B* pb=new C();
pb->func3();
pb是B型指针，但指向的是C类对象，并调用虚函数func3()。我们看一下这个函数调用在VC6.0编译器中编译出的代码（汇编语言的代码跟具体编译器有关，"；"后面部分是汇编语言的注释）：
mov edx, DWORD PTR _pb$[ebp]
；将this指针取出到edx中
mov eax, DWORD PTR [edx]
；将VPTR取出到eax中
mov esi, esp
；与本文无关，不用管它
mov ecx, DWORD PTR _pb$[ebp]
；将this指针作为参数传给函数
call DWORD PTR [eax+8]
；到VTABLE中查找，并进行调用
在这段代码中，寄存器edx存放的是对象的首地址，它对应该对象的this指针，因为每个成员函数调用都有个隐含参数，就是该对象的this指针。第一句是将this指针取出。因为VPTR保存在对象的首部，正是this指针指向的地址，所以第二句是将指向寄存器edx指向的位置的值，即this指针指向的双字，即VPTR取出，存在寄存器eax中。第三句与我们要讨论的没有关系，它是将堆栈指针保存起来，等该函数调用完返回后，进行检查，这是VC编译器的一种保护措施，我们不用管它。第四句就是将this指针作为参数传给这个函数。在汇编语言中，给一个函数传递参数可以有两种方法：通过堆栈或寄存器，一般比较小的函数调用或者经过优化后的程序会使用寄存器传参。第五句是去VTABLE表中查找虚函数位置，因为一个指针是四个字节，func3在表中是第三个，所以地址是eax＋8，然后进行调用。这样，编译器就实现了动态联编。