在問題引出(賦值相容性原則遇上函式重寫)在上節中我們說明了c++的繼承的時候,說明c++的繼承型別相容性原則:
子類物件可以當作父類物件使用
子類物件可以直接賦值給父類物件
子類物件可以直接初始化父類物件
父類指標可以直接指向子類物件
父類引用可以直接引用子類物件
但是如果子類定義了與父類中原型相同的函式會發生什麼?
函式重寫的概念
在子類中定義與父類中原型相同的函式,函式重寫只發生在父類與子類之間。
引入乙個**進行分析:
#include
using namespace std;
class parent};
class child : public parent};
void
test1
(parent *p)
void
test1
(parent& p)
intmain()
測試結果如下:
測試結果表示在子類對父類進行函式重寫後,賦值相容性原則遇上函式重寫。對於重寫的函式都是執行父類的成員函式。這一點並不是我們所希望的,我們更希望編譯器可以根據實際呼叫的物件來判斷重寫函式的呼叫。這一點就導致多型的機制的誕生,這個也是程式設計當中我們對於面對物件所提出新的需求----編譯器可以根據物件的不同來執行不同的重寫函式。
物件導向新需求:
還是上文相同的測試**
#include
using namespace std;
class parent};
class child : public parent};
void
test1
(parent *p)
void
test1
(parent& p)
intmain()
我們先舉乙個戰機pk的**來說明多型使用的優勢:
#include
using
namespace std;
#include
"iostream"
using
namespace std;
class
herofighter
// 英雄戰機};
class
advherofighter
:public herofighter // 英雄戰機2 };
class
enemyfighter
// 敵方戰機 };
void
objpk
(herofighter* hf, enemyfighter* enemyf)
else
}int
main()
這個**中有兩個英雄戰機,一種是herofighter
父類,一種是進化的英雄戰機advherofighter
子類重寫了父類herofighter
中的返回戰鬥力的函式。函式用virtual
表示這個函式是多型的。這樣我們寫得obpk
便可以通過物件的不同,來應用重名的不同函式,這樣好處不言而喻。回到面對物件的模型來講,面對物件有三個重要的特點封裝,繼承,多型。
封裝:突破了c語言函式的限制。
繼承:提高了**復用,也提高了程式設計的效率
多型:多型多型可以使用未來,80年**了乙個框架,90年寫的**可以應用於這個框架。 多型是軟體行業追尋的乙個目標,正如我們這個戰機的案例,我們可以寫3代戰機,4代戰機,n代戰機。他們的戰鬥力不同,但是我們可以通過通重寫函式並讓其多型,來實現功能。
多型成立的三個條件:
要有繼承
要有函式重寫
c 虛函式 要有父類指標(父類引用)指向子類物件
多型是設計模式的基礎,多型是框架的基礎理論知識:
1 多型的實現原理
下面我們通過幾張圖圖來闡述一下多型的實現原理:
當類中宣告虛函式時,編譯器會在類中生成乙個虛函式表
虛函式表是乙個儲存類成員函式指標的資料結構
虛函式表是由編譯器自動生成與維護的
virtual成員函式會被編譯器放入虛函式表中 存在虛函式時,每個物件中都有乙個指向虛函式表的指標(vptr指標)
說明1:
通過虛函式表指標vptr呼叫重寫函式是在程式執行時進行的,因此需要通過定址操作才能確定真正應該呼叫的函式。而普通成員函式是在編譯時就確定了呼叫的函式。在效率上,虛函式的效率要低很多。
說明2:
出於效率考慮,沒有必要將所有成員函式都宣告為虛函式
證明vptr指標的存在
在這裡插入**片#include
using
namespace std;
class
aprivate
:int a;};
class
bint a;};
intmain()
輸出結果:
顯然類b創立的物件b1比類a建立的物件新增乙個vptr指標變數(4個位元組)。
3 建構函式中能呼叫虛函式,實現多型嗎
物件中的vptr指標什麼時候被初始化?
物件在建立的時,由編譯器對vptr指標進行初始化
只有當物件的構造完全結束後vptr的指向才最終確定
父類物件的vptr指向父類虛函式表
子類物件的vptr指向子類虛函式表
#include
using
namespace std;
class
apublic
:virtual
void
print()
};classb:
public a
public
:virtual
void
print()
};intmain()
在vptr指標的初始化過程中,vtr指標先是指向父類的虛函式表,在父類函式初始化後,在指向子類的虛函式表。換句話說vptr指標的初始化是分步的,如圖所示。
c 多型總結
多型 多型可以簡單地概括為 乙個介面,多種方法 程式在執行時才決定呼叫的函式,它是物件導向程式設計領域的核心概念。接下來,我寫乙個簡單地函式來說明多型 includeusing namespace std int add int left,int right float add float left...
C 多型總結
多型繫結分兩種情況,一種是靜態繫結即編譯時多型,一種是動態繫結即執行時多型是利用過載實現的。對於非虛函式的成員來說,系統在編譯時,按照函式的引數的區別來繫結要實現的操作,在編譯時就確定了呼叫哪個函式。簡單地說,虛函式是動態繫結的基礎 動態繫結是實現執行時多型的基礎。要觸發動態繫結,需滿足兩個條件 1...
C 多型總結
多型概念 同乙個事物在不同環境下具有不同的狀態 虛函式概念 在函式返回值前加上 virtual 關鍵字 多型分類 靜態多型 早繫結 在編譯器編輯時確認要呼叫的函式 1 函式過載 2 泛型程式設計 動態多型 晚繫結 在程式執行時確認將要呼叫的函式 1 基類中存在虛函式 2 繼承當中對基類進行重寫並且 ...