【C++】多态(二)---------多态的调用原理和带有虚函数的对象模型

环境:win10+vs2015

为什么派生类对基类的虚函数进行重写后,通过基类对象的指针或引用来调用该虚函数,就可以实现多态呢?我们来探究一下多态的调用原理吧!

1.多态的调用原理:

如下代码:

#include<string>

class Base
{
public:
	virtual void TestFunc1()
	{
		cout << "Base::TestFunc1()" << endl;
	}
	virtual void TestFunc2()
	{
		cout << "Base::TestFunc2()" << endl;
	}
	virtual void TestFunc3()
	{
		cout << "Base::TestFunc3()" << endl;
	}

	int _b;
};

typedef void(*PVTF)();

//打印虚表
void Print(Base& b,string const& str)
{
	cout << str << endl;
	PVTF *pVTF = (PVTF*)*(int*)&b;	
	while (*pVTF)
	{
		(*pVTF)();
		pVTF++;
	}
	cout << endl;
}


class Derived :public Base
{
public:
	//新增TestFunc4
	virtual void TestFunc4()
	{
		cout << "Derived::TestFunc4()" << endl;
	}
	//重写TestFunc2
	virtual void TestFunc2()
	{
		cout << "Derived::TestFunc2()" << endl;
	}
	//重写TestFunc3
	virtual void TestFunc3()
	{
		cout << "Derived::TestFunc3()" << endl;
	}
	//新增TestFunc5
	virtual void TestFunc5()
	{
		cout << "Derived::TestFunc5()" << endl;
	}

	int _d;
};

int main()
{	
	cout << "Base类大小:"<<sizeof(Base) << endl;
	cout <<"Derived类大小:" <<sizeof(Derived) << endl;
	Base b;
	b._b = 1;

	Derived d;
	d._b = 1;
	d._d = 2;
	Print(b,"Base VFT:");
	Print(d,"Derived VFT:");
	return 0;
}

结果如下图:


分析:

单继承:

基类Base的大小为:8

(1)基类Base对象模型:

基类的虚函数表:将基类的中的虚函数按照声明的次序依次添加到虚表中


派生类大小为:12

(2)派生类对象模型:

派生类的虚函数表:

   a)将基类的虚函数表拷贝一份

   b)如果派生类重写了基类中的某个虚函数,用派生类虚函数替代相同偏移量位置的基类虚函数

   c)将派生类自己的新增加的虚函数添加到虚表的最后


(3)多态的调用原理:

a.从对象的前四个字节取出虚表的地址

b.传参(this+虚函数形参)

c.从虚表中取出虚函数地址

d.调用虚函数

2.不同继承模式下对象模型(带有虚函数)

(1)单继承

       上面已经探究过了

(2)多继承

//带有虚函数的多继承场景下派生类的对象模型&派生类的虚表
class B1
{
public:
	virtual void TestFunc1()
	{
		cout << "B1::TestFunc1" << endl;
	}
	virtual void TestFunc2()
	{
		cout << "B1::TestFunc2" << endl;
	}

	int _b1;
};

class B2
{
public:
	virtual void TestFunc3()
	{
		cout << "B2::TestFunc3" << endl;
	}
	virtual void TestFunc4()
	{
		cout << "B2::TestFunc4" << endl;
	}

	int _b2;
};

class Derived :public B1, public B2
{
public:
	virtual void TestFunc5()
	{
		cout << "D::TestFunc5" << endl;
	}

	virtual void TestFunc2()
	{
		cout << "D::TestFunc2" << endl;
	}

	virtual void TestFunc3()
	{
		cout << "D::TestFunc3" << endl;
	}

	virtual void TestFunc6()
	{
		cout << "D::TestFunc6" << endl;
	}
	int _d;
};

typedef void(*PVTF)();

//打印虚表
void Print(B1& b,string const& str)
{
	cout << str <<endl;
	PVTF *pVTF = (PVTF*)*(int*)&b;
	while (*pVTF)
	{
		(*pVTF)();
		pVTF++;
	}
	cout << endl;
}

void Print(B2 & b, string const& str)
{
	cout << str << endl;
	PVTF *pVTF = (PVTF*)*(int*)&b;
	while (*pVTF)
	{
		(*pVTF)();
		pVTF++;
	}
	cout << endl;
}

int main()
{
	cout << sizeof(Derived) << endl;

	Derived d;
	d._b1 = 1;
	d._b2 = 2;
	d._d = 3;
	B1& b1 = d;
	B2& b2 = d;
	Print(b1, "D VTF---->B1:");
	Print(b2, "D VTF---->B2:");
	return 0;
}

结果如下:


分析:


多继承模式下派生类的虚函数表:

   a)将基类的虚函数表拷贝一份

   b)如果派生类重写了基类中的某个虚函数,用派生类虚函数替代相同偏移量位置的基类虚函数

   c)将派生类自己的新增加的虚函数添加到第一张虚表的最后

(3)菱形继承(如图)

如下代码:

#include <string>
class B
{
public:
	virtual void TestFunc1()
	{
		cout << "B::TestFunc1" << endl;
	}
	virtual void TestFunc2()
	{
		cout << "B::TestFunc2" << endl;
	}

	int _b;
};

class C1 : public B
{
public:
	//重写B中的TestFunc1
	virtual void TestFunc1()
	{
		cout << "C1::TestFunc1" << endl;
	}
	//新增TestFunc3
	virtual void TestFunc3()
	{
		cout << "C1::TestFunc3" << endl;
	}
	int _c1;
};

class C2 : public B
{
public:
	//重写B中的TestFunc2
	virtual void TestFunc2()
	{
		cout << "C2::TestFunc2" << endl;
	}
	//新增TestFunc4
	virtual void TestFunc4()
	{
		cout << "C2::TestFunc4" << endl;
	}
	int _c2;
};

class D :public C1,public C2
{
public:
	//重写C1中的TestFunc1
	virtual void TestFunc1()
	{
		cout << "D::TestFunc1" << endl;
	}
	//重写C1中的TestFunc3
	virtual void TestFunc3()
	{
		cout << "D::TestFunc3" << endl;
	}
	//重写C2中的TestFunc4
	virtual void TestFunc4()
	{
		cout << "D::TestFunc4" << endl;
	}
	//新增TestFunc5
	virtual void TestFunc5()
	{
		cout << "D::TestFunc5" << endl;
	}
	int _d;
};

typedef void(*PVTF)();

void Print(C1 & b, string const& str)
{
	cout << str << endl;
	PVTF *pVTF = (PVTF*)*(int*)&b;
	while (*pVTF)
	{
		(*pVTF)();
		pVTF++;
	}
	cout << endl;
}

void Print(C2 & b, string const& str)
{
	cout << str << endl;
	PVTF *pVTF = (PVTF*)*(int*)&b;
	while (*pVTF)
	{
		(*pVTF)();
		pVTF++;
	}
	cout << endl;
}

int main()
{
	D d;
	d.C1::_b = 1;
	d.C2::_b = 2;
	d._c1 = 3;
	d._c2 = 4;
	d._d = 5;
	C1& c1 = d;
	C2& c2 = d;
	Print(c1, "D VTF--->C1");
	Print(c2, "D VTF--->C2");
	return 0;
}

结果:


分析:


(4)虚拟继承

(5)菱形虚拟继承


猜你喜欢

转载自blog.csdn.net/zimituanzi_/article/details/80938530