【摘要】
很多教材上都有介绍到虚指针、虚函数与虚函数表,有的说类对象共享一个虚函数表,有的说,一个类对象拥有一个虚函数表;还有的说,无论用户声明了多少个类对象,但是,这个VTABLE虚函数表只有一个;也有的在说,每个具有虚函数的类的对象里面都有一个VPTR虚函数指针,这个指针指向VTABLE的首地址,每个类的对象都有这么一种指针。今天,我们就来解决这个问题,同一个类的不同对象,是不是拥有“相同”的虚函数表,这个相同是物理上的相同(内存地址)还是逻辑上的相同(数据结构)。本文现详述如下!
【正文】
虚指针:每个含有虚方法(虚函数)对象里有虚表指针,指向虚表。
虚函数表:虚函数表是顺序存放虚函数地址的,虚表是顺序表,表里存放了虚函数的地址。
C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
【代码示例】
#include <iostream> using namespace std; class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout << "Base::h" << endl; } }; typedef void(*Fun)(void); int main() { Fun pFun = NULL; Base obj_1,obj_2; // obj_1 虚函数表 — 第一个函数 pFun = (Fun)*((int*)*(int*)(&obj_1)); pFun(); pFun = (Fun)*(((int*)*(int*)(&obj_1))+1); pFun(); // 输出 虚函数表地址 与 虚函数表元素 的值 cout << "obj_1 虚函数表地址:" << (int*)(&obj_1) << endl; cout << "obj_2 虚函数表地址:" << (int*)(&obj_2) << endl; cout << "obj_1 虚函数表 — 第一个函数地址:" << (int*)*(int*)(&obj_1) << endl; cout << "obj_2 虚函数表 — 第一个函数地址:" << (int*)*(int*)(&obj_2) << endl; return 0; } /* 输出 : Base::f Base::g obj_1 虚函数表地址:0018FF40 obj_2 虚函数表地址:0018FF3C obj_1 虚函数表 — 第一个函数地址:0046F0AC obj_2 虚函数表 — 第一个函数地址:0046F0AC Press any key to continue */
【结论】
不同对象虚函数表表中元素是相等的,逻辑上是一样的,存放的都是类中虚函数的地址;
不同对象虚函数表的内存地址是不一样,物理上是不一样的,一个对象是一个新的表。
【相关推荐】
详见:C++ 虚函数表解析
详址:http://blog.csdn.net/haoel/article/details/1948051#comments