C++中关于虚函数与虚函数表的理解

来源:互联网 发布:淘宝公司需要交税吗 编辑:程序博客网 时间:2024/05/16 17:38

在c++中多态性可大致分为两类:静态多态和动态多态。

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

每个含有虚函数的类有一张虚函数表(vtbl),该表是一个一维的数组,表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。没有虚函数的C++类,是不会有虚函数表的。

两张图:



下面是一些简单例子,是在vc6.0中编译的:

#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; }



0 0