标签:指针 大神 article rtti 例子 继承 rtu 图片 htm
? C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。
? 这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。
本文将详细介绍虚函数表的实现及其内存布局。
虚函数表是指在每个包含虚函数的类中都存在着一个函数地址的数组。当我们用父类的指针来操作一个子类的时候,这张虚函数表指明了实际所应该调用的函数。
C++的编译器保证虚函数表的指针存在于对象实例中最前面的位置,这样通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
按照上面的说法,来看一个实际的例子:
#include <iostream>
using namespace std;
class Base {
public:
virtual void f() { cout << "f()" << endl; }
virtual void g() { cout << "g()" << endl; }
virtual void h() { cout << "h()" << endl; }
};
int main()
{
Base t;
( ((void(*)())*((int*)(*((int*)&t)) + 0)) ) ();
( ((void(*)())*((int*)(*((int*)&t)) + 1)) ) ();
( ((void(*)())*((int*)(*((int*)&t)) + 2)) ) ();
return 0;
}
经过VS2017,x86测试:
我们成功地通过实例对象的地址,得到了对象所有的类函数。
main定义Base类对象t,把&b转成int *
,取得虚函数表的地址vtptr就是:(int*)(&t)
,然后再解引用并强转成int *
得到第一个虚函数的地址,也就是Base::f()即(int*)(*((int*)&t))
,那么,第二个虚函数g()的地址就是(int*)(*((int*)&t)) + 1
,依次类推。
下面我们来看下派生类没有覆盖基类虚函数的情况,其中Base类延用上一节的定义。从图中可看出虚函数表中依照声明顺序先放基类的虚函数地址,再放派生类的虚函数地址。
可以看到下面几点:
1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。
发现有很多优秀的大神写的更加详尽,具体可以参考以下链接:
https://coolshell.cn/articles/12165.html
https://jocent.me/2017/08/07/virtual-table.html
https://blog.csdn.net/lihao21/article/details/50688337
标签:指针 大神 article rtti 例子 继承 rtu 图片 htm
原文地址:https://www.cnblogs.com/Mered1th/p/10924545.html