在本文中,我们来学习C++中的虚函数表。很喜欢苏轼的《题西林壁》:

 

      横看成岭侧成峰,远近高低各不同。

      不识庐山真面目,只缘身在此山中。

 

     这首诗的哲理在于:对于同一个东西,从不同的角度看,结果是不一样的。下面来看一些铺垫性的程序:

 

#include <iostream>
using namespace std;

int main()
{
	float f = 3.14;
	cout << f << endl;              // 3.14
	cout << &f << endl;             // 0012FF7C 
	cout << (int *)(&f) << endl;    // 0012FF7C
	cout << *((int *)(&f)) << endl; // 1078523331

	return 0;
}
#include <iostream>
using namespace std;

int main()
{
	float **pp;
	float *p;
	float a = 10.5;
	p = &a;
	pp = &p;

	cout << pp << endl; // 0012FF78
	cout << p << endl;  // 0012FF74
	cout << a << endl;  // 10.5
	cout << "---------" << endl;

#define ADDR 0x0012ff78

	cout << (float **)ADDR << endl;     // 0012FF78
	cout << *(float **)ADDR << endl;    // 0012FF74
	cout << *(*(float **)ADDR) << endl; // 10.5
	cout << "---------" << endl;

	cout << (int **)ADDR << endl;       // 0012FF78
	cout << *(int **)ADDR << endl;      // 0012FF74
	cout << *(*(int **)ADDR) << endl;   // 1093140480
	cout << *((float *)(*(int **)ADDR)) << endl; // 10.5
	cout << "---------" << endl;

	return 0;
}
#include <iostream>
using namespace std;

int main()
{
	cout << (short *)0 + 1 << endl;    // 00000002
	cout << (int *)0 + 1 << endl;      // 00000004
	cout << (long *)0 + 1 << endl;     // 00000004
	cout << (float *)0 + 1 << endl;    // 00000004
	cout << (double *)0 + 1 << endl;   // 00000008

	return 0;
}

 

       搞懂了上面三个程序,就弄懂了苏轼的那首诗。同样的内存单元,不同的解析方式,可以得到不同的结果,下面来进入虚函数表的话题。看程序:

 

#include <iostream>
using namespace std;

class A
{
public:
	virtual void fun();
};

int main()
{
	cout << sizeof(A) << endl; // 4

	return 0;
}

     古怪,结果怎么会是4呢?这是虚指针在作怪!哪来的虚指针哦?看下面的程序:

 

 

#include <iostream>
using namespace std;

class E
{
public:

	// 为了方便叙述,故把公开a和b, 在实际系统中,很少这样做
	int a;
	int b;

    virtual void f()
	{
	};

    virtual void g()
	{
	};
};

int main()
{
	E e;
	e.a = 1;
	e.b = 2;
    cout << &e << endl;                    // e的VTABLE的地址:   0012FF74
	cout << (int *)&e << endl;             // eVPTR的地址:       0012FF74
	cout << &e.a << endl;                  // e.a的地址:        0012FF78
	cout << &e.b << endl;                  // e.b的地址:        0012FF7C

    cout << (void *)*((int *)&e) << endl;  // eVPTR的值          0046F028 
	cout << *((int *)&e + 1) << endl;      // e.a的值:           1
	cout << *((int *)&e + 2) << endl;      // e.b的值:           2

   
    cout << (void *)*(int *)(*(int *)&e) << endl;        // E的f函数的地址: 0040128A
	cout << (void *)*((int *)(*(int *)&e) + 1) << endl;  // E的g函数的地址: 004011B8
    
	cout << "---------" << endl;

	E ee;
	ee.a = 3;
	ee.b = 4;
    cout << &ee << endl;                   // ee的VTABLE的地址:  0012FF68
	cout << (int *)&ee << endl;            // eeVPTR的地址:     0012FF68
	cout << &ee.a << endl;                 // ee.a的地址:       0012FF6C  
	cout << &ee.b << endl;                 // ee.b的地址:       0012FF70 
   
	cout << (void *)*((int *)&ee) << endl; // eVPTR的值          0046F028 
	cout << *((int *)&ee + 1) << endl;     // ee.a的值:          3
	cout << *((int *)&ee + 2) << endl;     // ee.b的值:          4

    cout << (void *)*(int *)(*(int *)&ee) << endl;        // E的f函数的地址: 0040128A
	cout << (void *)*((int *)(*(int *)&ee) + 1) << endl;  // E的g函数的地址: 004011B8

	return 0;
}

      这个程序稍微有点复杂,下面,我们来画图分析:

 



        我们调试上述程序,得到下图:

       上述三个图,交相辉映,现在,有点明白虚函数表了吧。
 


本文转载:CSDN博客