如果子類定義了與父類中原型相同的函式會發生什麼?
例如class parent
public:
void print()
cout<<"i'm parent..."public:
void print()
cout<<"i'm child..."《使用時
child child;
child.print();
child.parent::print();
父類中被重寫的函式依然會繼承給子類,預設情況下子類中重寫的函式將隱藏父類中的函式,通過作用域分辨符::可以訪問到父類中被隱藏的函式
使用子類變數給父類指標賦值和引用賦值時
childchild;
parent *pp = &child;
parent &rp = child;
child.print();//iam child
pp->print();//iam parent
rp.print();//iam parent
c++與c相同,是靜態編譯型語言
在編譯時,編譯器自動根據指標的型別判斷指向的是乙個什麼樣的物件。所以編譯器認為父類指標指向的是父類物件(根據賦值相容性原則,這個假設合理),由於程式沒有執行,所以不可能知道父類指標指向的具體是父類物件還是子類物件從程式安全的角度,編譯器假設父類指標只指向父類物件,因此編譯的結果為呼叫父類的成員函式。
物件導向的新需求:據實際的物件型別來判斷重寫函式的呼叫,父類指標指向的是父類物件則呼叫父類中定義的函式,父類指標指向的是子類物件則呼叫子類中定義的重寫函式。
解決的辦法就是多型,
物件導向中的多型:
根據實際的物件型別決定函式呼叫語句的具體呼叫目標。
c++中的多型支援,
c++通過virtual關鍵字對多型進行支援,用virtual宣告的函式被重寫後即可展現多型特性。
父類的重寫函式經過virtual宣告後,父類指標指向子類後,呼叫的函式會是子類新定義的,由此實現了多型,據實際的物件型別來判斷重寫函式的呼叫,而不是父類指標只能指向父類的函式。
虛函式只有在繼承的時候才能體現它的作用。
重寫與過載的區別
函式過載:必須在同乙個類中進行,子類無法過載父類的函式,父類同名函式將被覆蓋,過載是
在編譯期間
根據引數型別和個數決定呼叫函式。
函式重寫:必須發生於父類與子類之間,並且父類與子類中的函式必須有完全相同的原型,使用
virtual
宣告之後能夠產生多型,多型是
在執行期間
根據具體物件的型別決定呼叫函式。
是否可以將類的每個成員函式都宣告為虛函式?
c++中多型的實現原理:當類中宣告虛函式時,編譯器會在類中生成乙個虛函式表,
虛函式表是乙個儲存類成員函式指標的資料結構,虛函式表是由編譯器自動生成與維護的
virtual成員函式會被編譯器放入虛函式表中,存在虛函式時,每個物件中都有乙個指向虛函式表的指標。
通過虛函式表指標vptr呼叫重寫函式是在程式執行時進行的,因此需要通過定址操作才能確定真正應該呼叫的函式。而普通成員函式是在編譯時就確定了呼叫的函式。在效率上,虛函式的效率要低很多。出於效率考慮,沒有必要將所有成員函式都宣告為虛函式。
物件中的vptr指標什麼時候被初始化?
物件在建立的時候由編譯器對vptr指標進行初始化
只有當物件的構造完全結束後
vptr
的指向才最終確定
父類物件的vptr指向父類虛函式表
子類物件的vptr指向子類虛函式表
結論:建構函式中呼叫虛函式無法實現多型。
純虛函式的使用:c++中使用純虛函式可以構造抽象類。
抽象類的直接特徵是純虛函式,抽象類不能用於定義物件,抽象類只能用於定義指標和引用,抽象類的純虛函式必須被子類重寫,抽象類的標誌就是純虛函式。
C 學習筆記之 多型
目錄應用 計算器類 純虛函式和抽象類 虛析構和純虛析構 型別轉換 多型性提供介面與具體實現之間的另一層隔離,將 什麼 和 怎麼做 分開 分類 動態多型 函式位址晚繫結 include using namespace std 動物類 class animal class dog public anim...
C 學習筆記 繼承與多型
1 關於繼承 inheritance 的概念 在c 中有 has a 和 is a 的 兩個概念。1.1 has a 即為在乙個類定義中包含另乙個類的物件 class a class b 1.2 is a 即我們說的繼承 如下,b繼承a,a為基類,b為a的派生類,b繼承了a的所有資料成員和成員函式。...
c 學習筆記( )繼承與多型
1.繼承的作用 復用 2.派生類繼承基類的什麼東西 除了基類的構造和析構函式以外的所有成員 3.public 任意位置都可以訪問 protected 本類類中,子類類中訪問 private 本類類中訪問 基類中不同的訪問限定符下的成員以不同的繼承方式在派生類中的訪問限定 public protect...