一篇文章彻底弄懂C++虚函数的实现机制
1、虚函数简介C中有两种方式实现多态即重载和覆盖。重载是指允许存在多个同名函数而这些函数的参数表不同参数个数不同、参数类型不同或者两者都不同。覆盖是指子类重新定义父类虚函数的做法简而言之就是用父类型别的指针指向其子类的实例然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针拥有“多种形态”这是一种泛型技术。所谓泛型技术说白了就是试图使用不变的代码来实现可变的算法比如模板元编程是在编译期完成的泛型技术RTTI、虚函数则是在运行时完成的泛型技术。关于虚函数的具体使用方法建议大家先去阅读相关的C的书籍本文只剖析虚函数的实现机制让大家对虚函数有一个更加清晰的认识并不对虚函数的具体使用方法作过多介绍。本文是依据个人经验和查阅相关资料最终编写的如有错漏希望大家多多指正。2、虚函数表简介学过C的人都应该知道虚函数Virtual Function是通过虚函数表Virtual Table简称为V-Table来实现的。虚函数表主要存储的是指向一个类的虚函数地址的指针通过使用虚函数表继承、覆盖的问题都都得到了解决。假如一个类有虚函数当我们构建这个类的实例时将会额外分配一个指向该类虚函数表的指针当我们用父类的指针来操作一个子类的时候这个指向虚函数表的指针就派上用场了它指明了此时应该使用哪个虚函数表而虚函数表本身就像一个地图一样为编译器指明了实际所应该调用的函数。指向虚函数表的指针是存在于对象实例中最前面的位置这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下这就意味着理论上我们可以通过对象实例的地址得到这张虚函数表实际上确实可以做到然后对虚函数表进行遍历并调用其中的函数。前面说了一大堆理论中看不中用下面还是通过一个实际的例子验证一下前面讲的内容首先定义一个Base类该类有三个虚函数代码如下1234567891011121314151617181920212223#include iostream#include stringtypedefvoid(*Fun)(void);classBase{public:virtualvoidf(){std::cout Base::f() std::endl;}virtualvoidg(){std::cout Base::g() std::endl;}virtualvoidh(){std::cout Base::h() std::endl;}};接下来按照前面的说法我们通过Base类的实例对象base来获取虚函数表代码如下1234567891011121314151617181920intmain(intargc,char* argv[]){Base base;Fun fun nullptr;std::cout 指向虚函数表指针的地址 (long*)(base) std::endl;std::cout 虚函数表的地址 (long*)*(long*)(base) std::endl;fun (Fun)*((long*)*(long*)(base));std::cout 虚函数表中第一个函数的地址 (long*)fun std::endl;fun();fun (Fun)*((long*)*(long*)(base) 1);std::cout 虚函数表中第二个函数的地址 (long*)fun std::endl;fun();fun (Fun)*((long*)*(long*)(base) 2);std::cout 虚函数表中第三个函数的地址 (long*)fun std::endl;fun();}运行结果图2-1所示Linux 3.10.0 GCC 4.8.5图2-1 程序运行结果在上面的例子中我们通过把base强制转换成long *来取得指向虚函数表的指针的地址然后对这个地址取值就可以得到对应的虚函数表了。得到对应虚函数表的首地址后就可以通过不断偏移该地址依次得到指向真实虚函数的指针了。这么说有点绕也有点晕下面通过一幅图解释一下前面说的内容详见图2-2图2-2 基类虚函数表内存布局当然上述内容也可以在GDB中调试验证后续的内容也将全部在GDB下直接验证调试的示例见图2-3图2-3 GDB查看基类虚函数表内存布局3、有继承关系的虚函数表剖析前面分析虚函数表的场景是没有继承关系的然而在实际开发中没有继承关系的虚函数纯属浪费表情所以接下来我们就来看看有继承关系下虚函数表会呈现出什么不一样的特点分析的时候会分别就单继承无虚函数覆盖、单继承有虚函数覆盖、多重继承、多层继承这几个场景进行说明。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2564957.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!