单继承和多继承的虚函数表

前面两篇关于多态的博客已经详细介绍了多态的基础知识点多态的底层实现原理,下面将主要介绍一下单继承和多继承的虚函数表~~~

一、单继承中的虚函数表

首先来看一段代码:

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	
private:
	int _b = 1;
};
class Derive :public Base
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
	virtual void Func3()
	{
		cout << "Derive::Func3()" << endl;
	}
	virtual void Func4()
	{
		cout << "Derive::Func4()" << endl;
	}
private:
	int _d = 2;
};
int main()
{
	Base b;
	Derive d;
	system("pause");
	return 0;
}

再来观察一下这段代码的调试窗口:

通过调试窗口可以看出派生类继承了基类的虚函数,并完成了覆盖,那么派生类自己的虚函数去哪了呢 ?这里是由于编译器的监视窗口故意隐藏了派生类的两个虚函数,给我们造成了误解,那我们又该如何看到派生类的两个虚函数呢?下面通过一段代码来看一下派生类的虚函数:

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	
private:
	int _b = 1;
};
class Derive :public Base
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
	virtual void Func3()
	{
		cout << "Derive::Func3()" << endl;
	}
	virtual void Func4()
	{
		cout << "Derive::Func4()" << endl;
	}
private:
	int _d = 2;
};
//函数指针
typedef void(*VFPTR)();
//传参传一个指针数组(虚表):VFPTR vTable[]==VFPTR* vTable
void PrintVTable(VFPTR vTable[])
{
	//依次取虚表中的虚函数指针打印并调用。调用之后就可以看出存的是哪个函数
	cout << "虚表地址->" << vTable << endl;
	for (int i = 0; vTable[i] != nullptr; ++i)
	{
		printf("第%d个虚函数表地址:0x%x,->", i, vTable[i]);
		VFPTR f = vTable[i];
		f();
	}
	cout << endl;
}
int main()
{
	Base b;
	Derive d;

	//取到基类的虚表地址
	VFPTR* bvTable = (VFPTR*)(*(int*)&b);
	PrintVTable(bvTable);

	//取到派生类的虚表地址
	VFPTR* dvTable = (VFPTR*)(*(int*)&d);
	PrintVTable(dvTable);

	system("pause");
	return 0;
}

解释一下这句代码:

VFPTR* bvTable = (VFPTR*)(*(int*)&b);

1、(int*)&b:取到基类的虚表地址,再强制转换成一个int*类型的指针

2、*(int*)&b:再解引用取头上4个字节

3、(VFPTR*)(*(int*)&b):再强制转换成VFPTR*,因为虚表就是一个存VFPTR类型(虚函数指针类型)的数组

需要注意的是这段打印虚表的代码有可能会崩溃,因为编译器有时对虚表的处理不干净,虚表最后面没有放nullptr,就会导致越界,这是编译器的问题,我们只需要清理解决方案就可以了。

输出结果:


从上述输出结果中,我们可以看到派生类的虚表中存了自己的虚函数和基类的虚函数。

二、多继承中的虚函数表

首先来看一段多继承的代码:

class Base1
{
public:
	virtual void Func1()
	{
		cout << "Base1::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base1::Func2()" << endl;
	}

private:
	int _b1 = 1;
};
class Base2
{
public:
	virtual void Func1()
	{
		cout << "Base2::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base2::Func2()" << endl;
	}

private:
	int _b2 = 1;
};
class Derive :public Base1,public Base2
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
	virtual void Func3()
	{
		cout << "Derive::Func3()" << endl;
	}
private:
	int _d1 = 2;
};
//函数指针
typedef void(*VFPTR)();
//传参传一个指针数组代表虚表:VFPTR vTable[]==VFPTR* vTable
void PrintVTable(VFPTR vTable[])
{
	//依次取虚表中的虚函数指针打印并调用。调用之后就可以看出存的是哪个函数
	cout << "虚表地址->" << vTable << endl;
	for (int i = 0; vTable[i] != nullptr; ++i)
	{
		printf("第%d个虚函数表地址:0x%x,->", i, vTable[i]);
		VFPTR f = vTable[i];
		f();
	}
	cout << endl;
}
int main()
{
	Derive d;

	VFPTR* b1vTable = (VFPTR*)(*(int*)&d);
	PrintVTable(b1vTable);

    //Base2的位置
	VFPTR* b2vTable = (VFPTR*)(*(int*)((char*)&d+sizeof(Base1)));
	PrintVTable(b2vTable);

	system("pause");
	return 0;

输出结果:

观察输出结果可知,多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中

猜你喜欢

转载自blog.csdn.net/yam_sunshine/article/details/89094676