虚函数之虚函数表

多态性可分为两类:静态多态和动态多态。函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的。

每个含有虚函数的类有一张虚函数表(vtbl),表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。

没有虚函数的C++类,是不会有虚函数表的。

两张图:

 

 简单例子:

 

#include <iostream>
#include <windows.h>

using namespace std;

class base
{
    virtual void f(){cout<<"base::f"<<endl;};
    virtual void g(){cout<<"base::g"<<endl;};
    virtual void h(){cout<<"base::h"<<endl;};
};

typedef void (*pfun)();

void main()
{
    DWORD w=0x4011e0; //虚函数表第一项的内容,也就是第一个虚函数的地址

    pfun fun=NULL;
    base b;
    base *pbase=&b;

    fun=(pfun)w;
    fun();    //调用第一个虚函数
}


 

查看对象b在内存中:

查看虚函数表:

 

 虚函数表的指针4个字节大小(vptr),存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

 

虚函数表的结束标志在不同的编译器下是不同的。在VC6.0下,这个值是NULL,如图:

 

 


另一个例子:

 

#include <iostream>

using namespace std;

class base
{
    virtual void f(){cout<<"base::f"<<endl;};
    virtual void g(){cout<<"base::g"<<endl;};
    virtual void h(){cout<<"base::h"<<endl;};
};

class Derive : public base
{
    
public:
    Derive(){};
    virtual void f() { cout << "Derive::f" << endl; }    
    virtual void g() { cout << "Derive::g" << endl; }
    
};

typedef void(*pfun)();

void main()
{
    pfun fun=NULL;
    Derive d;
    base *p=&d;

    fun=(pfun)**((int**)p);
    fun();    //调用第一个虚函数

    fun=(pfun)*(*((int**)p)+2);
    fun();    //调用第三个函数

}


 

查看对象d在内存中:

 


多重继承:

   有几个父类,就有几个vtab和vptr

 

 

 

#include <iostream>
 
using namespace std;
 
class Base1 {
 
public:
 
            virtual void f() { cout << "Base1::f" << endl; }
 
            virtual void g() { cout << "Base1::g" << endl; }
 
            virtual void h() { cout << "Base1::h" << endl; }
 
 
 
};
 
class Base2 {
 
public:
 
            virtual void f() { cout << "Base2::f" << endl; }
 
            virtual void g() { cout << "Base2::g" << endl; }
 
            virtual void h() { cout << "Base2::h" << endl; }
 
};
 
 
class Base3 {
 
public:
 
            virtual void f() { cout << "Base3::f" << endl; }
 
            virtual void g() { cout << "Base3::g" << endl; }
 
            virtual void h() { cout << "Base3::h" << endl; }
 
};
 
 
class Derive : public Base1, public Base2, public Base3 {
 
public:
 
            virtual void f() { cout << "Derive::f" << endl; }
 
            virtual void g1() { cout << "Derive::g1" << endl; }
 
};
 
 
typedef void(*Fun)(void);
 
int main() 

{
 
            Fun pFun = NULL;
 
            Derive d;
 
            int** pVtab = (int**)&d;
 
            //Base1's vtable
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+0);
 
            pFun = (Fun)pVtab[0][0];
 
            pFun();
 

            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+1);
 
            pFun = (Fun)pVtab[0][1];
 
            pFun();
 

            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+2);
 
            pFun = (Fun)pVtab[0][2];
 
            pFun();
 

            //Derive's vtable
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+0)+3);
 
            pFun = (Fun)pVtab[0][3];
 
            pFun();
 
 
            //The tail of the vtable
 
            pFun = (Fun)pVtab[0][4];
 
            cout<<pFun<<endl;
 
 
            //Base2's vtable
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
 
            pFun = (Fun)pVtab[1][0];
 
            pFun();
 
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
 
            pFun = (Fun)pVtab[1][1];
 
            pFun();
 

            pFun = (Fun)pVtab[1][2];
 
            pFun(); 

 
            //The tail of the vtable
 
            pFun = (Fun)pVtab[1][3];
 
            cout<<pFun<<endl;
 
 
            //Base3's vtable
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+0);
 
            pFun = (Fun)pVtab[2][0];
 
            pFun();
 
 
            //pFun = (Fun)*((int*)*(int*)((int*)&d+1)+1);
 
            pFun = (Fun)pVtab[2][1];
 
            pFun();
 
 
            pFun = (Fun)pVtab[2][2];
 
            pFun(); 

 
            //The tail of the vtable
 
            pFun = (Fun)pVtab[2][3];
 
            cout<<pFun<<endl;
 
 
            cout<<sizeof(d)<<endl;

            return 0;
 
}


原文博客地址:http://www.cnblogs.com/Ripper-Y/archive/2012/05/15/2501930.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值