C++虚函数表的底层原理 & 到底有几张虚函数表? & 虚函数表是怎么维护的?

Posted 狱典司

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++虚函数表的底层原理 & 到底有几张虚函数表? & 虚函数表是怎么维护的?相关的知识,希望对你有一定的参考价值。

昨天读了陈皓前辈博客中关于虚函数表底层原理的一篇博客,本着实践出真知的出发点,遂写了相应的测试代码去检验,发现最后测试出来的结果和陈皓博客中说明的情况存在出入。目前尚不清楚是不同编译器底层实现原理不同还是整个标准已经迭代(距离那篇博客的发布时间已经过去15年了),欢迎一样有求知欲的伙伴同僚也把代码拿去测试,一起分享心得!

博客原文:C++ 虚函数表解析

目前我只在DevC++(32位)上做了测试,还没来得及在Linux上做测试(我的Linux是64位的,指针大小为8Bytes),以下是我的测试代码和测试结果:

# include <bits/stdc++.h>
using namespace std;

//typedef void(*Fun)(void) //(C风格)
using Fun = void(*)(void); //(C++11风格)
/* 基类 1 */
class Base
public:
	virtual void f() cout << "f() of class Base\\t"; 
	virtual void g() cout << "g() of class Base\\t"; 
	virtual void h() cout << "h() of class Base\\t"; 
;
/* 基类 2 */
class DupBase
public:
	virtual void f() cout << "f() of class DupBase\\t"; 
	virtual void g() cout << "g() of class DupBase\\t"; 
	virtual void h() cout << "h() of class DupBase\\t"; 
; 

/* 一般继承且不重写父类虚函数 */
class Derive : public Base
;

/* 一般继承,重写父类虚函数 */
class Derive_rewrite : public Base
	void f() cout << "f() of class Derive_rewrite, , which is rewritten\\t"; 
; 

/* 多重继承且不重写父类虚函数 */
class MulDerive : public Base, DupBase	
;

/* 多重继承,重写父类虚函数 */
class MulDerive_rewrite : public Base, DupBase
	void f() cout << "f() of class MulDerive_rewrite, which is rewritten\\t"; 
;

void testAll()
	/*-------------------- 测试:基类 -----------------------*/
	Base b;	
	cout << endl;
	cout << "基类 Base的vfptr指针(内容指向vftable地址):" <<  (int *)(&b) << endl;
	
	cout << "基类 Base的虚函数表:" <<endl;
	Fun pFun = (Fun)*((int*)*(int*)(&b)+0);  cout <<"Base 调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&b)+0) << endl; 
	pFun = (Fun)*((int*)*(int*)(&b)+1);  cout <<"Base 调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&b)+1) << endl; 
	pFun = (Fun)*((int*)*(int*)(&b)+2);  cout <<"Base 调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&b)+2) << endl; 
	cout << "结束符:" <<  (Fun *)*((int*)*(int*)(&b) + 3 ) << endl;
	
	/*---------------------测试:一般继承且不重写父类虚函数----------------------*/
	Derive d;
	cout << endl << "一般继承,子类不重写父类虚函数的情况下:"<< endl; 
	cout << "子类 Derive的vfptr指针(内容指向vftable地址):" <<  (int *)(&d) << endl;
	
	cout << "子类 Derive的虚函数表:" <<endl;
	pFun = (Fun)*((int*)*(int*)(&d)+0);  cout <<"Derive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&d)+0) << endl; 
	pFun = (Fun)*((int*)*(int*)(&d)+1);  cout <<"Derive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&d)+1) << endl; 
	pFun = (Fun)*((int*)*(int*)(&d)+2);  cout <<"Derive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&d)+2) << endl; 
	cout << "结束符:" <<  (Fun *)*((int*)*(int*)(&d) + 3 ) << endl;
	
	/*-------------------- 测试:一般继承,重写父类虚函数 -----------------------*/
	Derive_rewrite dr;
	cout << endl << "一般继承,子类重写父类虚函数的情况下:"<< endl; 
	cout << "子类 Derive_rewrite的vfptr指针(内容指向vftable地址):" <<  (int *)(&dr) << endl;
	cout << "子类 Derive_rewrite的虚函数表:" <<endl;
	/* 父类指针or引用指向父类对象的虚函数入口,也就是父类对象调用的虚函数 */
	pFun = (Fun)*((int*)*(int*)(&dr)+0);  cout <<"Derive_rewrite调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&dr)+0) << endl; 
	pFun = (Fun)*((int*)*(int*)(&dr)+1);  cout <<"Derive_rewrite调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&dr)+1) << endl;
	pFun = (Fun)*((int*)*(int*)(&dr)+2);  cout <<"Derive_rewrite调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&dr)+2) << endl;
	
	cout << "结束符:" <<  (Fun *)*((int*)*(int*)(&dr) + 3 ) << endl;
	
	/*-------------------- 多重继承,不重写父类虚函数 -----------------------*/
	MulDerive md;
	cout << endl << "多重继承,子类不重写父类虚函数的情况下:"<< endl; 
	cout << "子类 MulDerive的第一个vfptr指针(内容指向MulDerive类继承自Base类的vftable地址):" <<  (int *)(&md) << endl;
	cout << "子类 MulDerive的第二个vfptr指针(内容指向MulDerive类继承自DupBase类的vftable地址):" <<  (int *)(&md)+1 << endl;
	
	cout << "子类 MulDerive继承自Base类的vftable:" <<endl;
	pFun = (Fun)*((int*)*(int*)(&md)+0);  cout <<"MulDerive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md)+0) << endl; 
	pFun = (Fun)*((int*)*(int*)(&md)+1);  cout <<"MulDerive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md)+1) << endl; 
	pFun = (Fun)*((int*)*(int*)(&md)+2);  cout <<"MulDerive调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md)+2) << endl; 
	cout << "结束符:" <<  (Fun *)*((int*)*(int*)(&md) + 3 ) << ", 非0,表明还存在下一个vfptr" << endl;
	
	cout << "子类 MulDerive继承自DupBase类的vftable:" <<endl;
	pFun = (Fun)*((int*)*((int*)(&md)+1)+0);  cout <<"MulDerive调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md+1)+0) << endl;
	pFun = (Fun)*((int*)*((int*)(&md)+1)+1);  cout <<"MulDerive调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md+1)+1) << endl;
	pFun = (Fun)*((int*)*((int*)(&md)+1)+2);  cout <<"MulDerive调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(&md+1)+2) << endl;
	cout << "结束符:" <<  (Fun)*((int*)*((int*)(&md)+1)+3) << endl;
	
	/*-------------------- 测试:多重继承,不重写父类虚函数 -----------------------*/
	MulDerive_rewrite mdr;
	cout << endl << "多重继承,子类重写父类虚函数的情况下:"<< endl; 
	cout << "子类 MulDerive_rewrite的第一个vfptr指针(内容指向MulDerive_rewrite类继承自Base类的vftable地址):" <<  (int *)(&mdr) << endl;
	cout << "子类 MulDerive_rewrite的第二个vfptr指针(内容指向MulDerive_rewrite类继承自DupBase类的vftable地址):" <<  (int *)(&mdr)+1 << endl;
	
	cout << "子类 MulDerive_rewrite继承自Base类的vftable:" <<endl;
	pFun = (Fun)*((int*)*(int*)(&mdr)+0);  cout <<"MulDerive_rewrite调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&mdr)+0) << endl; 
	pFun = (Fun)*((int*)*(int*)(&mdr)+1);  cout <<"MulDerive_rewrite调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&mdr)+1) << endl; 
	pFun = (Fun)*((int*)*(int*)(&mdr)+2);  cout <<"MulDerive_rewrite调用:"; pFun();  cout << "入口地址:" << (Fun *)*((int*)*(int*)(&mdr)+2) << endl; 
	cout << "结束符:" <<  (Fun *)*((int*)*(int*)(&mdr) + 3 ) << endl;
	
	cout << "子类 MulDerive继承自DupBase类的vftable:" <<endl;
	pFun = (Fun)*((int*)*((int*)(&mdr)+1)+0);  cout <<"MulDerive_rewrite调用:"; pFun(); cout << "入口地址:" << (Fun *)*((int*)*(int*)(《C++多态的底层原理和虚函数表的那些事 一》

虚函数指针和虚函数表

多态实现原理剖析

C++ 多态 : 虚函数静态绑定动态绑定单/多继承下的虚函数表

C++ 多态 : 虚函数静态绑定动态绑定单/多继承下的虚函数表

C++ 多态 : 虚函数静态绑定动态绑定单/多继承下的虚函数表