9-4:C++多态之单继承和多继承中的虚函数表

Posted 快乐江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9-4:C++多态之单继承和多继承中的虚函数表相关的知识,希望对你有一定的参考价值。

(1)单继承中的虚函数表

如下继承体系中,fun1函数重写,fun2未被重写,B类中fun3和fun4也被定义为了虚函数

#include <iostream>
#include <stdio.h>
using namespace std;

class A
{
public:
	virtual void fun1()
	{
		cout << "fun(1)" << endl;
	}
	virtual void fun2()
	{
		cout << "fun(2)" << endl;
	}
private:
	int _a= 1;
};

class B : public A
{
public:
	virtual void fun1()
	{
		cout << "Test2:fun1" << endl;
	}
	virtual void fun3()
	{
		cout << "Test2:fun2" << endl;
	}
	virtual void fun4()
	{
		cout << "Test2:fun2" << endl;
	}
private:
	int _b = 2;

};

通过之前的叙述我们知道,对象的第一个指针是虚函数表指针,而虚函数表实则是一个函数指针数组,所以我们可以利用下面的方式将虚函数的地址打印出来,并且通过显示调用的方式直接调用虚函数。

typedef void(*VFUN)();//定义了一个函数指针的类型

void PrintVtf(VFUN* fun)
{
	for (int i = 0; fun[i] != nullptr; i++)
	{
		printf("第%d个虚函数地址为:0x%x,通过地址调用->", i, fun[i]);
		VFUN f = fun[i];
		f();//取到地址直接调用虚函数
	}
	cout << endl;
}

int main()
{
	A a;
	B b;

	VFUN* va = (VFUN*)(*((int*)&a));
	/*
		取a的地址强转为int*,然后解引用取值拿到头4个字节,它就是指向虚函数表的
		指针,再次强转VFUN*,虚伪虚函数表就是存储一个VFUN类型的函数指针数组
		接着传递给PrintVtf打印,同时利用函数地址直接调用
	*/
	PrintVtf(va);

	VFUN* vb = (VFUN*)(*((int*)&b));
	PrintVtf(vb);


}

结果显示如下
在这里插入图片描述
在这里插入图片描述

(2)多继承中的虚函数表

这两篇文章对于C++的多态,虚函数有着深入的探究

C++虚函数表解析
C++对象的内存分布

多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中

如下多继承体系中,子类重写了fun1,继承了fun2,自己存在一个虚函数fun3

typedef void(*VFT)();

void PrintVFT(VFT *vftarr)
{
	printf("虚表指针:%p\\n", vftarr);
	for (int i = 0; vftarr[i] != nullptr; i++)
	{
		printf("vftarr[%d]:%p->", i, vftarr[i]);
		VFT f = vftarr[i];
		f();
		cout << endl;
	}
}

//多继承


class base1 {
public:
	virtual void func1() { cout << "base1::func1" << endl; }
	virtual void func2() { cout << "base1::func2" << endl; }
private:
	int b1;
};
class base2 {
public:
	virtual void func1() { cout << "base2::func1" << endl; }
	virtual void func2() { cout << "base2::func2" << endl; }
private:
	int b2;
};

class derive : public base1, public base2 {
public:
	//重写func1,继承func2,自己写一个func3
	virtual void func1() { cout << "derive::func1" << endl; }
	virtual void func3() { cout << "derive::func3" << endl; }
private:
	int d1;
};

int main()
{
	derive d;

	cout << "大小" << sizeof(d) << endl;// 8 + 8 +4 =20

	printf("func1真实地址:%p\\n", &derive::func1);//成员函数取地址要加&

	PrintVFT((VFT*)(*(int*)&d));//取b1基表指针
	cout << "___________" << endl;
	PrintVFT((VFT*)(*(int*)((char*)&d + sizeof(base1))));//取b2基表指针

	printf("func1真实地址:%p\\n", &derive::func1);//成员函数取地址要加&

	system("pause");
	return 0;
}

运行结果如下
在这里插入图片描述
可以发现,在上面的继承体系中子类会继承两个虚函数表指针,子类没有重写的虚函数则放在第一个继承基类部分的虚函数表中

以上是关于9-4:C++多态之单继承和多继承中的虚函数表的主要内容,如果未能解决你的问题,请参考以下文章

C++:多态(重写,多态原理单继承和多继承的虚函数表)

C++多态

C++多态

C++多态详解

C++多态详解

C++——多态