我是靠谱客的博主 欢喜煎饼,最近开发中收集的这篇文章主要介绍C++虚表的实现原理(windows & linux上),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

当大家被问到C++多态是怎么实现的时候,一般也就想到了虚函数吧,进一步也就是想到了与其关联的虚表指针,那我们就该想想这个虚表到底是怎么做到的呢。

/*author:  Jeson Yang
 date:	2015.11.21
 file:	****.cpp*/

#include <iostream>
using namespace std;

#define __stdcall
class CBase
{
public:
	virtual void f(){ cout << "f()" << endl; };
	virtual void g(){ cout << "g()" << endl; };
	virtual int i(int nNum){ cout << "i() - " << nNum << endl; return 0; };
	void m(){ cout << "m()" << endl; };		//混淆视听的非虚函数
	virtual void h(){ cout << "h()" << endl; };
};

int main()
{
	CBase cb;
	typedef void(__stdcall *pFun)();
	typedef int(__stdcall *pFun1)(int);		//告诉编译器使用远的C函数吧,不加可能出错喔			

	pFun f;
	pFun1 f1;
	int *vPtr = (int*)&cb;		//虚表指针喽
	int *vFun = (int*)((int*)*vPtr + 1);	//通过虚表找到的 指向第二个虚函数地址的指针
	f = (pFun)*vFun;	//通过虚表找到的 第二个虚函数地址
	//f = (pFun)*(int*)((int*)*vPtr + 1);
	//f = (pFun)*(int*)((int*)*(int*)&cb + 1);
	f();	//打印g()
	
	f1 = (pFun1)*(int*)((int*)*vPtr + 2);	//跟上面的差不多吧
	f1(100);	//打印i() -100

	f = (pFun)*(int*)((int*)*vPtr + 3);	//函数m在前面,但是不是虚函数,所以跳过喽
	f();	//打印h()

	//关于越界后面改成+4(算是结束点吧) windows7+vs2013为NULL
	//linux据说有些环境f值为1表示有下一个虚表,0表示结束吧</span>待考证
	//本人linux好像结果不一致

return 0;
}
具体根据这个注释走一遍,关于这种最简单结构的虚表的结构应该能画出来吧。

 

 

如果以上能完全理解了,下面就可以看看有多重继承关系的结构了,个人对于画图不怎么在行,也就只好通过注释来理解了,不便见谅。

 <pre class="cpp" name="code">/*author:  Jeson Yang 
 date:  2015.11.21 
 file:  ****.cpp*/  
  
#include <iostream>  
using namespace std;  
  
#define __stdcall  
class CBase  
{  
public:  
    virtual void f(){ cout << "f()" << endl; };  
    virtual void g(){ cout << "g()" << endl; };  
    virtual int i(int nNum){ cout << "i() - " << nNum << endl; return 0; };  
    void m(){ cout << "m()" << endl; };     //混淆视听的非虚函数  
    virtual void h(){ cout << "h()" << endl; };  
    //int m_nNum;       //linux上可以打开  
};  
  
class CBase1  
{  
public:  
    virtual void f(){ cout << "f1()" << endl; };  
};  
  
class cDerive : public CBase,public CBase1  
{  
public:  
    void f(){ cout << "derive f()" << endl; };      //自动虚,覆盖基类的f()  
private:  
  
};  
  
int main()  
{  
    cDerive cb;  
    typedef void(__stdcall *pFun)();  
    typedef int(__stdcall *pFun1)(int);     //告诉编译器使用远的C函数吧,不加可能出错喔  
                  
    pFun f;  
    int **vPtr = (int**)&cb;      
  
    cout << sizeof(cDerive) << endl;  
    f = (pFun)vPtr[0][0];   //通过虚表找到的 指向第一个虚函数地址的指针  
    f = (pFun)*(int*)(*(int*)((int*)&cb + 0) + 0);  
    //f = (pFun)(int*)&cb;  
    f();    //打印f1(),多态的实现,函数指针的覆盖  
      
    f = (pFun)*(int*)(*(int*)((char*)&cb + sizeof(CBase)) + 0);   
    //此处写法为了适应linux(centos5.6 g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-55))上  
    //打开CBase里面的int参数  
    //windows上并不适用  
  
    f();    //打印f1(),多态的实现,函数指针的覆盖  
  
    return 0;  
}  

 

 

当然虚表实现也有些不足,假如将以上f()设置private 以上依旧能够访问,这也是十分危险的,故windows linux上都通过

windows上应该加了些保护机制吧,对于基类中有一些其他成员变量的好像不能通过指针计算偏移的方式访问到吧,如果能够做到或者有什么错误希望能留言联系吧

 

 

 

最后

以上就是欢喜煎饼为你收集整理的C++虚表的实现原理(windows & linux上)的全部内容,希望文章能够帮你解决C++虚表的实现原理(windows & linux上)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部