虛基類
在說明其作用前先看一段**
classa;
class b
:publica;
};classc:
publica;
};classd:
public b
,publicc;
};void
main()
從**中可以看出類b c都繼承了類a的ivalue成員,因此類b c都有乙個成員變數ivalue ,而類d又繼承了b c,這樣類d就有乙個重名的成員 ivalue(乙個是從類b中繼承過來的,乙個是從類c中繼承過來的).
在主函式中呼叫d.ivalue 因為類d有乙個重名的成員ivalue編譯器不知道呼叫 從誰繼承過來的ivalue所以就產生的二義性的問題.正確的做法應該是加上作用域限定符 d.b::ivalue 表示呼叫從b類繼承過來的ivalue。不過 類d的例項中就有多個ivalue的例項,就會占用記憶體空間。所以c++中就引用了虛基類的概念,來解決這個問題。
classa;
class b
:virtual
publica;
};classc:
virtual
publica;
};classd:
public b
,publicc;
};void
main()
在繼承的類的前面加上virtual關鍵字表示被繼承的類是乙個虛基類,它的被繼承成員在派生類中只保留乙個例項。例如ivalue這個成員,從類 d這個角度上來看,它是從類b與類c繼承過來的,而類b c又是從類a繼承過來的,但它們只保留乙個副本。因此在主函式中呼叫d.ivalue時就不 會產生錯誤。
虛函式
還是先看**
classa;
};class b
:publica;
};void
main()
大家以為這段**的輸出結果是什麼?有的人可能會馬上回答funprint of class a 與 funprint of class b 因為第一次輸出是引用類a的實 例啊,第二次輸出是引用類b的例項啊。那麼我告訴你這樣想就錯啦,答案是funprint of class a 與 funprint of class a 至於為什麼輸出 這樣的結果不在本文討論的範圍之內;你就記住,不管引用的例項是哪個類的當你呼叫的時候系統會呼叫左值那個物件所屬類的方法。比如說 上面的**類a b都有乙個funprint 函式,因為p是乙個a類的指標,所以不管你將p指標指向類a或是類b,最終呼叫的函式都是類a的funprint 函式。這就是靜態聯篇,編譯器在編譯的時候就已經確定好了。可是如果我想實現跟據例項的不同來動態決定呼叫哪個函式呢?這就須要用到 虛函式(也就是動態聯篇)。
classa;
};class b
:publica;
};void
main()
多型性可分為兩類:靜態多型和動態多型。函式過載和運算子過載實現的多型屬於靜態多型,動態多型性是通過虛函式實現的。
每個含有虛函式的類有一張虛函式表(vtbl),表中每一項是乙個虛函式的位址, 也就是說,虛函式表的每一項是乙個虛函式的指標。
沒有虛函式的c++類,是不會有虛函式表的。
兩張圖:
在基類的成員函式前加virtual關鍵字表示這個函式是乙個虛函式,所謂虛函式就是在編譯的時候不確定要呼叫哪個函式,而是動態決定將要調 用哪個函式,要實現虛函式必須派生類的函式名與基類相同,引數名引數型別等也要與基類相同。但派生類中的virtual關鍵字可以省略,也表 示這是乙個虛函式。下面來解決一下**,宣告乙個基類的指標(必須是基類,反之則不行)p,把p指向類a的例項a,呼叫funprint函式,這 時系統會判斷p所指向的例項的型別,如果是a類的例項就呼叫a類的funprint函式,如果是b類的例項就呼叫b類的funprint函式。
純虛函式
與其叫純虛函式還不如叫抽象類,它只是宣告乙個函式但不實現它,讓派生類去實現它,其實這也很好理解。
class
vehicle
;class
camion
:public
vehicle;};
class
bike
:public
vehicle;};
void
main()
如上**,定義了乙個交通工具類(vehicle),類中有一函式可列印出交通工具的輪胎個數,但交通工具很多輪胎個數自然也就不確定,所以 就把它定義為純虛函式,也就是光定義函式名不去實現它,類camion繼承了vehicle並實現了裡面的**,列印出有4個輪胎。bike類也是一樣。 有一點須要注意一下,純虛函式不能實化化,但可以宣告指標。
總結
虛基類
1, 乙個類可以在乙個類族中既被用作虛基類,也被用作非虛基類。
2, 在派生類的物件中,同名的虛基類只產生乙個虛基類子物件,而某個非虛基類產生各自的子物件。
3, 虛基類子物件是由最派生類的建構函式通過呼叫虛基類的建構函式進行初始化的。
4, 最派生類是指在繼承結構中建立物件時所指定的類。
5, 派生類的建構函式的成員初始化列表中必須列出對虛基類建構函式的呼叫;如果未列出,則表示使用該虛基類的預設建構函式。
6, 從虛基類直接或間接派生的派生類中的建構函式的成員初始化列表中都要列出對虛基類建構函式的呼叫。但只有用於建立物件的最派生 類的構造函式呼叫虛基類的建構函式,而該派生類的所有基類中列出的對虛基類的建構函式的呼叫在執行中被忽略,從而保證對虛基類子物件 只初始化一次。
7, 在乙個成員初始化列表中同時出現對虛基類和非虛基類建構函式的呼叫時,虛基類的建構函式先於非虛基類的建構函式執行。
虛函式
1, 虛函式是非靜態的、非內聯的成員函式,而不能是友元函式,但虛函式可以在另乙個類中被宣告為友元函式。
2, 虛函式宣告只能出現在類定義的函式原型宣告中,而不能在成員函式的函式體實現的時候宣告。
3, 乙個虛函式無論被公有繼承多少次,它仍然保持其虛函式的特性。
4, 若類中乙個成員函式被說明為虛函式,則該成員函式在派生類中可能有不同的實現。當使用該成員函式操作指標或引用所標識的物件時 ,對該成員函式呼叫可採用動態聯編。
5, 定義了虛函式後,程式中宣告的指向基類的指標就可以指向其派生類。在執行過程中,該函式可以不斷改變它所指向的物件,呼叫不同 版本的成員函式,而且這些動作都是在執行時動態實現的。虛函式充分體現了物件導向程式設計的動態多型性。 純虛函式 版本的成員函式,而且這些動作都是在執行時動態實現的。虛函式充分體現了物件導向程式設計的動態多型性。
純虛函式
1, 當在基類中不能為虛函式給出乙個有意義的實現時,可以將其宣告為純虛函式,其實現留待派生類完成。
2, 純虛函式的作用是為派生類提供乙個一致的介面。
3, 純虛函式不能實化化,但可以宣告指標。
虛基類 虛函式 純虛函式講解
虛基類 在說明其作用前先看一段 從 中可以看出類b c都繼承了類a的ivalue成員,因此類b c都有乙個成員變數ivalue 而類d又繼承了b c,這樣類d就有乙個重名的成員 ivalue 乙個是從類b中繼承過來的,乙個是從類c中繼承過來的 在主函式中呼叫d.ivalue 因為類d有乙個重名的成員...
虛基類 虛函式和純虛基類
首先看乙個例子 class base class child1 public base class child2 public base void main else p print 函式呼叫的時候,檢視虛表,根據p的位址首先從虛表裡面查詢要呼叫的函式 這裡呼叫child2的print 函式 ret...
虛函式 虛基類 純虛函式 友元
虛基類 當在多條繼承路徑上有乙個公共的基類,在這些路徑中的某幾條匯合處,這個公共的基類就會產生多個例項 或多個副本 若只想儲存這個基類的乙個例項,可以將這個公共基類說明為虛基類.classx1 virtual public x classx2 virtual public x 虛函式實際上,優秀的程...