【面试】虚函数原理

 
 

概述

含有虚函数的类,其实例化的对象都包括一个虚函数表指针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实际应该有三个虚函数,但是这里并没有体现出来第三个。


程序运行结果

 
 

猜你喜欢

转载自blog.csdn.net/zamely/article/details/80583764