微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

虚函数表剖析

函数表的研究

有如下四个类定义

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;

首先,这四个类是在一个继承链中,他们各有一个函数表(因为他们之中都存在虚函数)。

以下是各类实例的虚函数表地址:
vbase
0x0046f064(vbase 的虚函数表占 20 字节 )

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();
base* b2 = new base();
base* b3 = new base();

b2和b3的虚函数表指针的值将于b1相同。


扩展:

看一下如下的实现:

Base* pbase=new a;

pbase->fun1();

此时是以基类指针调用 fun1 ,如果 fun1 是普通函数,毫无疑问,应该调用 base::fun1 。但 fun1 为虚函数,存在于虚函数表中,在 new a 的时候, new 的是 a 对象及其虚函数表,所以,调用的是 a::fun1 。这就是虚函数的妙用。

多重继承中,虚函数表的研究:

以上代码展示了一个简单的多重继承例子。


看一下实际内存数据:
1、
MyIH的内存首地址为0x0012ff50(通过监视& MyIH得到

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

原文地址:https://www.jb51.cc/vb/262025.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐