C++——多型

audience_fzn發表於2018-08-07

1.什麼是多型?

多型簡單的講就是“一個介面,多種方法”,程式在執行時才決定呼叫的函式,他是物件導向的核心概念。當多型應用形參的資料交,可以接受更多的型別,當多型用於返回值型別的時候,可以返回更多型別的資料,多型可以讓你的程式碼擁有更好的擴充套件性

構成多型的條件

  • 繼承的存在
  • 子類要重寫父類的虛擬函式
  • 父類的指標/引用呼叫重寫虛擬函式

什麼是重寫:

  • 不在同一作用域內(分別在父類和子類中)
  • 基類函式必須是虛擬函式(virtual關鍵字)
  • 函式名相同,引數相同,返回值相同(協變除外)
  • 訪問修飾符可以不同(公有,保護…)

場景一:父類和子類都加virtual:

class person
{
public:
	virtual void buytickets()
	{
		cout << "買票" << endl;
	}
};

class student :public person
{
public:
	virtual void buytickets()
	{
		cout << "買票——半價" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父類物件
	student s;//子類物件
	Fun(p);
	Fun(s);
}

輸出為: 

當使用基類的指標或引用呼叫重寫的虛擬函式時,當指向父類物件呼叫的就是父類的虛擬函式,指向子類的物件就是呼叫子類的虛擬函式。

多型跟型別無關,跟物件有關

場景二:基類中函式不加virtual

構成多型時,父類的函式必須是虛擬函式(virtual),為什麼

class person
{
public:
	void buytickets()
	{
		cout << "買票" << endl;
	}
};

class student :public person
{
public:
	virtual void buytickets()
	{
		cout << "買票——半價" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父類物件
	student s;//子類物件
	Fun(p);
	Fun(s);
}
  • 輸出為:

  • 如果將父類的virtual,那麼就不能構成多型,即使你建立了子類物件和父類物件,呼叫的也都是父類的函式//輸出“買票”。與物件無關,不能構成多型
  • 而如果將子類中的virtual去掉,而父類中的還在,同樣可以構成多型。 

場景三:派生類中函式不加virtual

class person
{
public:
	virtual void buytickets()
	{
		cout << "買票" << endl;
	}
};

class student :public person
{
public:
	void buytickets()
	{
		cout << "買票——半價" << endl;
	}
};

void Fun(person& p)
{
	p.buytickets();
}

void Test()
{
	person p;//父類物件
	student s;//子類物件
	Fun(p);
	Fun(s);
}

輸出為:

 

2.多型的分類:

  • 編譯時的多型性(靜態多型):靜態多型就是過載,因為是在編譯時即確定型別大小,所以稱為靜態多型。
  • 執行時多型性(多型多型):通過繼承重寫基類的虛擬函式實現,在程式執行時決議確定,所以稱為動態

動態多型:上述程式碼即使動態多型

每一個帶有虛擬函式的物件都會有一個虛擬函式表,虛擬函式表裡存的時函式指標,呼叫的時候,指標就去虛擬函式表裡查詢。

發生重寫之後,下一次父類指向我們呼叫的fun()函式時,它呼叫到的就是子類的fun()函式。

多型:

  • 多型是物件導向的三大特徵直以,分為靜態多型和多型多型
  • 靜態多型包含函式過載與泛型程式設計,靜態多型是程式呼叫函式,編譯器決定使用那塊可執行程式碼塊
  • 動態多型是由繼承機制及虛擬函式實現的,通過指向派生類的基類指標或引用,訪問派生類中透明覆蓋成員函式
  • 多型的作用:把不同的子類物件都當作父類來看,可以遮蔽不同子類物件之間的差異,寫出通用的程式碼,做出通用的程式設計,一適應需求的不斷變化。

 

類成員函式中過載/重定義(隱藏)/重寫(覆蓋)的區別

1.函式過載:通常是一組功能相似但是引數型別不同的函式

  • 函式要在相同的作用域中
  • 函式名相同
  • 函式的引數列表不同(引數個數,引數順序,引數型別),與返回值無關

 2.函式覆蓋(重寫):覆蓋是指在派生類裡覆蓋基類的函式

  • 函式在不同作用域中(基類和派生類)
  • 倆個函式名相同/引數相同/返回值相同(協變除外)
  • 基類必須是虛擬函式(派生類最好也是)
  • 訪問修飾符可以不同

3.函式隱藏(重定義):派生類的函式遮蔽了與其名字相同的基類函式

  • 函式的作用域不同(基類,派生類)
  • 函式名相同(只要名字相同就可以構成隱藏)
  • 如果派生類函式與基類函式引數相同,但是基類中沒有virtual,就構成函式隱藏

 

 

相關文章