虚函数表剖析
虚函数表的研究 有如下四个类定义: class base { public: virtual void fun1(); virtual void fun2(); virtual void fun3(); virtual void fun5(); };
class a:public base { public: void fun1(); virtual void fun4(); };
class b:public base { public: void fun1(); };
class d:public a { };
下面分析一下各类实例初始化时,虚函数表的结构。
有如下定义: base vbase; a va; b vb; d vd;
首先,这四个类是在一个继承链中,他们各有一个虚函数表(因为他们之中都存在虚函数)。 以下是各类实例的虚函数表地址: Va : 0x0046f078(va 的虚函数表占 24 字节 ) Vb : 0x0046f090(vb 的虚函数表占 20 字节 ) Vd : 0x0046f0a4(vd 的虚函数表占 24 字节 )
其次,虚函数表中的元素,都是函数指针,每个元素占 4 字节。 依次类推, vbase 中有 5 个虚函数, va 中有 6 个, vb 中有 5 个, vd 中有 6 个。 但是实际上的数量应该是, 4 、 5 、 4 、 5 。 为什么会引起这种现象,来看一下虚函数表中到底存了些什么数据,以下是实际结果, vc 中截取: Vbase : 0x004010af 、 0x00401032 、 0x0040112c 、 0x004010a5 、 0x00000000 Va : 0x00401190 、 0x00401032 、 0x0040112c 、 0x004010a5 、 0x00401186 、 0x00000000 Vb : 0x0040118b 、 0x00401032 、 0x0040112c 、 0x004010a5 、 0x00000000 Vd : 0x00401190 、 0x00401032 、 0x0040112c 、 0x004010a5 、 0x00401186 、 0x00000000
看一下这些值指向的是什么函数: 0x004010af : base::fun1() 0x00401032 : base::fun2(); 0x0040112c : base::fun3(); 0x004010a5 : base::fun5(); 0x00401186 : a::fun4(); 0x00401190 : a::fun1(); 0x0040118b : b::fun1();
文字替换一下,很容易得出结论: 1、 每个类的虚函数表结尾会有一空元素,标示此表的结束。 2、 每个类都有一张独立的虚函数表 3、 子类继承父类,会新建一张虚函数表,并将父类的虚函数表拷贝过来。如果改写了虚函数,则将自己的表中元素相应改写,指向被改写的函数。 4、 类的多个实例会共享类的虚函数表。 例如: base* b1 = new base(); b2和b3的虚函数表指针的值将于b1相同。
扩展: 看一下如下的实现: Base* pbase=new a; pbase->fun1(); 此时是以基类指针调用的 fun1 ,如果 fun1 是普通函数,毫无疑问,应该调用 base::fun1 。但 fun1 为虚函数,存在于虚函数表中,在 new a 的时候, new 的是 a 对象及其虚函数表,所以,调用的是 a::fun1 。这就是虚函数的妙用。 多重继承中,虚函数表的研究:
以上代码展示了一个简单的多重继承例子。
看一下实际内存数据: 2、MyIH有两张虚函数表,则它的头8个字节是虚函数表地址:2c 78 41 00 1c 78 41 00。 则两张表的实际地址为:0x0041782c和0x0041781c。 3、 0x0041782c中的数据:49 12 41 00 58 12 41 00 00 00 00 00 分析得到: 0x00411249:b1f1的地址 0x00411258:b1f2的地址 0x00000000:结束标示符 4、 0x0041781c中的数据:3c 10 41 00 2d 10 41 00 00 00 00 00 分析得到: 0x0041103c:b2f1的地址 0x0041102d:b2f2的地址 0x00000000:结束标示符 得出结论:
对于对象MyIH 1、有两张虚函数表,分别从base1和base2继承 2、两张表的顺序,遵循类定义中的继承先后顺序,即第一张表是继承于base1的,第二张表继承于base2 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |