探索c++虚函数表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了探索c++虚函数表相关的知识,希望对你有一定的参考价值。

c++中多态的实现

我们都知道,c++中的多态是在虚函数的基础上实现的,用指向派生类的基类指针调用派生类(或基类)中自己的成员函数。那么,具体是怎么实现的呢?

其实它是通过虚函数表来实现的,虚函数表是保存虚函数地址的一张表,若一个类中有虚函数,当程序运行时,编译器通过在虚函数表中查找相应的虚函数的地址来调用该函数。

 

对象的继承有如下几类:

1.单一继承

2.多重继承

3.重复继承(钻石继承)

4.虚继承

下面我们分别来看一下各种继承的内存布局:

 

单一继承

 

技术分享

单一继承的结构

运行下面这段程序:

#include<iostream>
using namespace std;
typedef void(*PFUN)();
class B
{
public:
     B() :_b(0){}
     virtual void fun1()
     {
          cout << "B::fun1()" << endl;
     }
     virtual void fun2()
     {
          cout << "B::fun2()" << endl;
     }    
private:
     int _b;
};
class D:public B
{
public:
     D() :_d(1){}
     void fun1()
     {
          cout << "D::fun1()" << endl;
     }
     virtual void fun3()
     {
          cout << "D::fun3()" << endl;
     }
private:
     int _d;
};
void PrintVT(int b)//根据虚函数表中的函数地址调用虚函数
{
     PFUN pfun = NULL;
     int *ptr = (int *)b;
     int i = 0;
     while (ptr[i])
     {
          pfun = (PFUN)ptr[i];//将虚函数的地址转换为函数指针
          pfun();//用函数指针调用函数
          i++;
     }
}
int main()
{
     D d;
     PrintVT(*(int *)&d);//取出虚函数表的地址
     getchar();
     return 0;
}

我们在内存窗口可以看到:

技术分享

上面程序的功能是调用虚函数表中函数的地址所对应的函数,程序运行结果如下:

 

 技术分享

现在我们可以知道单一继承的内存布局了

技术分享

                                                                     单一继承对象模型

单一继承的内存布局是:

1)对象的最前面放的是虚函数表的地址,然后根据继承的顺序依次放置成员变量的地址。

2)虚表里按继承顺序先放置派生类从基类继承来的虚函数的地址,然后是派生类自己的虚函数的地址。

3)满足覆盖条件的派生类的虚函数地址覆盖了基类虚函数的地址。

 

覆盖:

1)不同作用域(基类和派生类中)

2)函数名相同,参数列表相同,返回值类型相同(协变除外)

3)为虚函数(virtual)

注:协变是指基类虚函数返回值为基类类型的指针,派生类虚函数的返回值为派生类类型的指针

 

多重继承

未完待续。。。

 

 

 

 

 

 

 

以上是关于探索c++虚函数表的主要内容,如果未能解决你的问题,请参考以下文章

C++——多态

探索C++对象模型

C++多态

C++之多态总结(多态的定义及实现,抽象类,多态原理,单继承,多继承中的虚函数表)

9-3:C++多态之多态的实现原理之虚函数表,虚函数表指针静态绑定和动态绑定

C++多态详解