概述
含有虚函数的类,其实例化的对象都包括一个虚函数表指针vptr(virtual table pointer,虚函数表指针),该指针就在对象的开始,也就是说对象的地址就是虚函数指针的地址。
而虚函数指针指向了虚函数表。虚函数表实际上就是所有虚函数的地址数组,4B表示一个虚函数地址(入口)。
构造过程
引用:https://www.cnblogs.com/malecrab/p/5572730.html
验证代码
验证环境为Win7 64位操作系统 + VS2010 旗舰版
#include <iostream> using namespace std; class Parent{ public: long b; virtual void foo() {cout << "Parent foo" << endl;}; virtual void bar() {cout << "Parent bar" << endl;}; }; class Son : public Parent{ public: long d; virtual void bar() {cout << "Son bar" << endl;}; virtual void quz() {cout << "Son quz" << endl;}; }; typedef void(*pFunc)(void); int main() { Parent p; Son s; p.b = 100; s.b = 200; s.d = 300; pFunc pFun = NULL; cout << "父类虚函数表指针地址 0x" << (int*)(&p) << endl; cout << "父类虚函数表地址: 0x" << (int*)*(int*)(&p) << endl; cout << "父类第一个虚函数地址:0x" << (int*)*(int*)*(int*)(&p)<< endl; cout << "父类第二个虚函数地址:0x" << (int*)*(int*)(*(int*)(&p) + 4)<< endl; cout << "子类虚函数表指针地址 0x" << (int*)(&s) << endl; cout << "子类虚函数表地址: 0x" << (int*)*(int*)(&s) << endl; cout << "子类第一个虚函数地址:0x" << (int*)*(int*)*(int*)(&s)<< endl; cout << "子类第二个虚函数地址:0x" << (int*)*(int*)(*(int*)(&s) + 4)<< endl; cout << "子类第三个虚函数地址:0x" << (int*)*(int*)(*(int*)(&s) + 8)<< endl; //父类第一个虚函数指针 pFun = (pFunc)*(int*)*(int*)(&p); pFun(); //父类第二个虚函数指针 pFun = (pFunc)*(int*)(*(int*)(&p) + 4); pFun(); //子类第一个虚函数指针 pFun = (pFunc)*(int*)*(int*)(&s); pFun(); //子类第二个虚函数指针 pFun = (pFunc)*(int*)(*(int*)(&s) + 4); pFun(); //子类第三个虚函数指针 pFun = (pFunc)*(int*)(*(int*)(&s) + 8); pFun(); return 0; }
动态调试
在内存中检视父类的地址&p,输入'&p'后自动转换为0x39FD04。可以看到该地址的4B为0xb47938,就是虚函数表指针的值。
我们看这个地址,指向的区域就是虚函数表了。可以看到分别是0xb411f4,0xb41032.
子类是一样的,就不赘述了。
下面看下父类和子类的对象,VS中的值。可以看到vfptr的构成。但是子类对象s实际应该有三个虚函数,但是这里并没有体现出来第三个。