C++中关于虚函数与虚函数表的理解
2014-10-06 17:26
337 查看
在c++中多态性可大致分为两类:静态多态和动态多态。
函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的。
每个含有虚函数的类有一张虚函数表(vtbl),该表是一个一维的数组,表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。没有虚函数的C++类,是不会有虚函数表的。
两张图:
下面是一些简单例子,是在vc6.0中编译的:
查看虚函数表:
虚函数表的指针4个字节大小(vptr),存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
注意:虚函数表的结束标志在不同的编译器下是不同的。在VC6.0下,这个值是NULL
另外再补充一个例子
查看对象d在内存中:
在多重继承中的情况:
有几个父类,就有几个vtab和vptr
具体的代码如下:
函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的。
每个含有虚函数的类有一张虚函数表(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; }
相关文章推荐
- 关于C++——理解C++默默编写并调用了哪些函数&&函数初始化式(初始化列表相关)
- C++中关于构造函数调用次序的一道经典例题及对虚函数构造顺序的理解
- 写写本人关于c/c++的引用,指针,虚函数的理解
- 关于C++默认打开函数的理解
- 关于C++多态与虚函数的理解
- 关于C++中在函数中按值返回、临时对象、拷贝构造函数的一点理解
- C++中虚函数的理解,以及简单继承情况下的虚函数的表!
- c++对于虚函数,纯虚函数,普通函数的理解
- 关于C++虚函数与普通函数的编译与调用机制
- 关于c++的静态数据(函数)成员的理解
- 关于C++虚函数自己的理解
- 关于C++中静态成员函数的理解
- 关于C++中函数指针的使用
- 关于c++ const 函数参数
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 关于C++ Primer Plus书中讲的:隐式实例化,显示实例化,显示具体化的理解.
- c++多重继承和虚继承及虚函数深入理解
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- 一劳永逸:关于C/C++中指针、数组与函数复合定义形式的直观解释
- 关于C++中函数指针的使用(包含对typedef用法的讨论)