多態

多態調用需要滿足:1、虛函數的重寫,2、對象時基類的指針或引用,當滿足這兩點時才說明是多態。
虛函數—類的成員函數前面加上virtual關鍵字,則這個成員函數成爲虛函數。
虛函數重寫—子類定義了與父類相同的虛函數時,則就稱子類重寫了父類的這個虛函數。
先來一段代碼:

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

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人全價" << endl;
	}

};

class Student : public Person
{
	virtual void BuyTicket()
	{
		cout << "學生半價" << endl;
	}

};

void func(Person& p)
{
	p.BuyTicket();
}

int main()
{
	Person p;
	Student s;
	func(p);
	func(s);
	system("pause");
	return 0;
}

來看看運行結果
在這裏插入圖片描述
注意:這邊子類即派生類就是與父類函數名相同的可以不使用virtual,因爲子類繼承了父類public的內容。
多態調用:與調用的對象有關,指向那個對象虛函數調用就是誰的。還是以上面的代碼爲例
看看調試的監視窗口
在這裏插入圖片描述
此時有一個指針變量_vfptr,p的第一個元素他指向的是Person所對應的BuyTicket();函數,s繼承父類此時這個指針指向student類裏的BuyTicket();函數。
_vfptr指針其實是虛表指針,這個虛表指針是在構造函數中初始化的,虛表是在編譯時生成的,虛表沒有固定的存儲的區域有時是在靜態區或是數據常量區,一般是在靜態區。
沒有成員的類的大小爲1,但是在多態中是4。
看代碼

int main()
{
	Person p;
	Student s;
	/*func(p);
	func(s);*/
	cout << sizeof(p) << endl;
	cout << sizeof(s) << endl;
	system("pause");
	return 0;
}

把上面的主函數改改看看運行結果
在這裏插入圖片描述
總結:
1、子類(派生類)重寫父類(基類)的虛函數實現多態,要求函數名、參數列表、返回值完全相。(協變除外)
協變:
虛函數重寫的特殊情況,返回值可以不同,但必須是父子類的指針或引用
2、子類重寫的虛函數可以不寫virtual (C++語法比較不嚴謹的地方)
3、只有類的成員函數可以定義爲虛函數。
4、靜態成員函數不能定義爲虛函數。因爲靜態沒有this指針,沒有對象可以調用,但虛函數必須要有對象才能找到虛表
5、operator=(沒有意義) 參數不同
6、析構函數(最好是虛函數)也是重寫和隱藏的特例
看代碼

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

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人全價" << endl;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
};

class Student : public Person
{
	virtual void BuyTicket()
	{
		cout << "學生半價" << endl;
	}

	~Student()
	{
		cout << "~Stduent()" << endl;
	}
};

int main()
{
	Person *p=new Student;
	delete p;
	system("pause");
	return 0;
}

看看結果
在這裏插入圖片描述
若不重寫虛函數則只調用~person()
若重寫了虛函數那麼會先調用~student,最後調用person的析構函數

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

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人全價" << endl;
	}

	virtual ~Person()
	{
		cout << "~Person()" << endl;
	}
};

class Student : public Person
{
	virtual void BuyTicket()
	{
		cout << "學生半價" << endl;
	}

	virtual ~Student()
	{
		cout << "~Stduent()" << endl;
	}
};

int main()
{
	Person *p=new Student;
	delete p;
	system("pause");
	return 0;
}

在這裏插入圖片描述
析構函數之所以可以實現隱藏,是因爲析構函數名在編譯時被替換成了destructor函數名,這兩個父子類相同的虛函數就是同一份貨。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章