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
- C++中关于虚函数与虚函数表的理解
- 关于虚函数的理解
- 关于C语言中main()函数的理解
- C语言中关于gets和scanf函数的理解
- c语言中,关于延迟函数的理解
- c语言中,关于延迟函数的理解
- c语言中,关于延迟函数的理解
- c语言中,关于延迟函数的理解
- c语言中,关于延迟函数的理解
- c语言中,关于延迟函数的理解
- stm32中关于NVIC_SetVectorTable函数使用的疑惑与理解
- C++:虚函数理解
- 【C/C++】理解虚基类、虚函数与纯虚函数的概念
- c语言关于strlen函数的理解
- 关于多态性和虚函数的理解
- 关于C++虚函数自己的理解
- 关于C中函数声明与定义
- c的回调函数与java中抽象函数,接口函数,抽象类简单理解
- 法国和家庭已截图语言
- dghtyjt6uik68uik
- Unity3D中随机函数的应用
- FAQ03127 MTK修改代码编绎命令
- ListView视图缓存错位问题
- C++中关于虚函数与虚函数表的理解
- 北大青鸟代码---asp.net初学者宝典
- 设计模式之观察者模式-Observer
- poj 1466 Girls and Boys (最大独立集)
- 对编码的认识与想法
- libvirt架构及源码分析
- 初学C#_4
- 算法导论7.4-5
- string was not declared in this scope问题解决方法