1. 程式人生 > >多型呼叫的原理

多型呼叫的原理

問題:為什麼派生類對基類的虛擬函式重寫,通過基類物件的指標或引用>呼叫該虛擬函式,就可以實現多型

因為有序函式的類的物件模型的前四個位元組儲存的是一個地址,這個地址指向的是一個虛擬函式表,表中的內容是虛擬函式的地址。

在這裡插入圖片描述


#include <iostream>
#include <string>
using namespace std;

typedef void(*PVFT)();     //定義一個函式指標

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


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

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

	int _b;
};

void printVTF(Base& b,const string& desc)
{
	//(&b)  //取類b的地址(指標)
	//(int*)(&b)  //因為需要前四個位元組的內容,所以對其強轉為(int*)
	//*(int*)(&b)  //將前四個位元組的內容取到
	//(PVFT*)*(int*)(&b)  //將前四個位元組的內容取到作為地址
	//賦值給函式指標
	cout <<desc<< endl;
	PVFT* PV = (PVFT*)*(int*)(&b);
	while (*PV)
	{
		(*PV)();
		++PV;
	}
	
}

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

	Base b;
	b._b = 10;

	printVTF(b,"Base");
	system("pause");
	return 0;
}

普通函式:直接呼叫

虛擬函式的呼叫(滿足多型條件)

  1. 從物件前4個位元組中取虛表的地址
  2. 傳遞this指標
  3. 從虛表中獲取虛擬函式的地址(在虛表地址+虛擬函式在虛表中的偏移量)
  4. 呼叫虛擬函式

單繼承

  1. 基類有虛擬函式,繼承基類,派生類將基類的虛表拷貝到自己的虛表中
  2. 派生類某個虛擬函式如果重寫基類的虛擬函式,替代相同偏移量位置的虛擬函式為子類的虛擬函式
  3. 如果派生類新增加自己特有的虛擬函式,將其放在基類繼承下來虛擬函式的後面。
#include <iostream>
#include <string>
using namespace std;

typedef void(*PVFT)();

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


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

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

	int _b;
};

void printVTF(Base& b, const string& desc)
{
	//(&b)  //取類b的地址(指標)
	//(int*)(&b)  //因為需要前四個位元組的內容,所以對其強轉為(int*)
	//*(int*)(&b)  //將前四個位元組的內容取到
	//(PVFT*)*(int*)(&b)  //將前四個位元組的內容取到作為地址
	//賦值給函式指標
	cout << desc << endl;
	PVFT* PV = (PVFT*)*(int*)(&b);
	while (*PV)
	{
		(*PV)();
		++PV;
	}

}

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

	virtual void TestFunc3()
	{
		cout << "Derived::TestFunc3()" << endl;
	}
	int _d;
};

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

	Derived d;
	d._b = 1;
	d._d = 2;

	printVTF(d, "Deived VIF:");
	system("pause");
	return 0;
}

帶有虛擬函式的多繼承物件的模型以及虛表

  1. 多繼承,將派生類自己的新增加的虛擬函式新增到第一張虛表最後
#include <iostream>
#include <string>
using namespace std;

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 D:public B1, public B2
{
public:
	virtual void TestFunc1()
	{
		cout << "D::TestFunc1" << endl;
	}

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

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

typedef void(*PVTF)();
void PrintVTF(B1& b,const string& str)    //不能傳值(不是外面的實體),必須指標或引用,
{
	PVTF* PV = (PVTF*)(*(int*)&b);
	cout << str << endl;
	while (*PV)
	{
		(*PV)();
		++PV;
	}
}

void PrintVTF(B2& b, const string& str)    //不能傳值(不是外面的實體),必須指標或引用,
{
	PVTF* PV = (PVTF*)(*(int*)&b);
	cout << str << endl;
	while (*PV)
	{
		(*PV)();
		++PV;
	}
}


int main()
{
	cout << sizeof(D) << endl;
	D d;
	d._b1 = 1;
	d._b2 = 2;
	d._d = 3;

	B1& b1 = d;
	PrintVTF(b1,"D VTF of B1");

	B2& b2 = d;
	PrintVTF(b2, "D VTF of B2");


	system("pause");
	return 0;
}

在這裡插入圖片描述 上面程式碼的輸出結果 在這裡插入圖片描述

帶有虛擬函式的菱形繼承

#include <iostream>
#include <string>
using namespace std;

class B
{
public:
	virtual void TestFunc1()
	{
		cout << "B::TestFunc1()" << endl;
	}

	virtual void TestFunc2()
	{
		cout << "B::TestFunc2()" << endl;
	}
	int _b;
};

class C1 : public B
{
public:
	virtual void TestFunc1()
	{
		cout << "C1::TestFunc1()" << endl;
	}

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

	int _c1;
};

class C2 : public B
{
public:
	virtual void TestFunc2()
	{
		cout << "C2::TestFunc2()" << endl;
	}

	virtual void TestFunc4()
	{
		cout << "C2::TestFunc4()" << endl;
	}
	int _c2;
};


class D : public C1, public C2
{
public:
	virtual void TestFunc3()
	{
		cout << "D::TestFunc3()" << endl;
	}

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

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

	int _d;
};

typedef void(*PVTF)();
void PrintVTF(C1& b, const string& str)    //不能傳值(不是外面的實體),必須指標或引用,
{
	PVTF* PV = (PVTF*)(*(int*)&b);
	cout << str << endl;
	while (*PV)
	{
		(*PV)();
		++PV;
	}
}

void PrintVTF(C2& b, const string& str)    //不能傳值(不是外面的實體),必須指標或引用,
{
	PVTF* PV = (PVTF*)(*(int*)&b);
	cout << str << endl;
	while (*PV)
	{
		(*PV)();
		++PV;
	}
}

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

	D d;
	d.C1::_b = 0;
	d._c1 = 1;

	d.C2::_b = 2;
	d._c2 = 3;
	d._d = 4;

	C1& c1 = d;
	PrintVTF(c1,"D VTF of c1");

	C2& c2 = d;
	PrintVTF(c2, "D VTF of c2");

	system("pause");
	return 0;
}

在這裡插入圖片描述

在這裡插入圖片描述