1. 程式人生 > >C++面向物件高階程式設計(上) 第三週 侯捷 類與類之間的關係

C++面向物件高階程式設計(上) 第三週 侯捷 類與類之間的關係

組合與繼承

Composition(複合)

類中有類  Adapter(一種設計模式名)

所有的功能都在的deque中完成了,queue想擁有deque的功能,就這麼做。

queue裡面,只實現了呼叫個deque的功能,並沒有實現deque的全部功能。

Composition從記憶體的角度看

Composition(複合)關係下的構造和解構函式

構造的過程中,系統呼叫的是預設的建構函式,如果你希望呼叫別的建構函式,你需要自己想呼叫的建構函式以及函式裡面的引數,這樣編譯器才能知道你要呼叫哪一個建構函式。

Delegation委託  Composition by reference

用指標相連的話,他們的生命不一致。在composition關係中,兩個類同生共死。在delegation中,我需要呼叫你的時候,才會建立你。

上圖中的兩個類,左邊就是Handle,右邊就是Body。外界只能看見Handle

Handle中的指標可以指向不同的實現類,這就有了一種彈性。右邊的類,無論怎麼動都不影響左邊,也就是不影響客戶端。這個手法又叫做編譯防火牆

如果要跟人家共享,切記,千萬不能牽一髮而動全域性。也就是說,這裡abc要共享這個hello,如果a把hello修改了,不能影響b和c對於hello的應用。

解決辦法就是,當a想對hello修改的時候,系統就單獨拿出一份來讓a修改。這個概念就是copy on write

Inheritance 繼承  is -a

父類的資料是被完整繼承下來的。(上圖中的子類不僅僅有自己的_M_data,還有父類的那兩個指標_M_next和_M_prev)。

父類函式的呼叫權也被繼承下來。

Inheritance(繼承)關係下的構造和析構

子類的物件有父類的成分

Inheritance(繼承) with virtual function(虛擬函式)

子類擁有呼叫父類成員函式的呼叫權。

在main裡面,建立一個子類物件,通過子類物件呼叫父類函式

至於上圖中,為什麼執行到Serialize()的時候就跑去CMyDoc中去呼叫virtual Serialize()  :

由於呼叫OnFileOpen()的是myDoc,所以呼叫實際可以寫成:

。誰呼叫的,this就指向誰,所以myDoc的地址就傳入呼叫的函式OnFileOpen()中去了(圖中沒有寫出來,是因為傳的是this隱藏指標,成員函式都有一個this隱藏指標,該指標由編譯器替我們寫,我們不用寫)。

在呼叫Serialize()的時候,編譯器眼中是如圖所示:

Serialize()是通過this來呼叫,而this是誰,this是myDoc。MyDoc就是如圖所示:

因此,Serialize()是通過this來呼叫,而this是上圖所示,所以函式執行到Serialize()的時候就跑去CMyDoc中去呼叫virtual Serialize()。

請自己去檢驗一下,如下圖所示的兩種關係中,記憶體的分佈情況如何(可以通過觀察系統呼叫構造函式的順序來判斷)

Delegation(委託)+Inheritance(繼承)

希望對於同一個資料,用多種不同的視窗,通過不同的方式進行觀察,解決辦法如下:

相應的實現原理如下:

Composite

在容器裡面放的東西要一樣的大小,所以容器裡面放的不是物件、不是東西,而是指標(即Componet*),因為指標是一樣的大小

在Component中,沒有把add函式設計成純虛擬函式,因為,如果你設計成純虛擬函式,那麼子類就一定要去定義它。而左側的子類primitive,沒有辦法去做加的動作,因此沒有把add寫成純虛擬函式。

Prototype

當希望建立未來的子類物件的時候,此事並不知道子類的類名,解決辦法就是:子類都建立一個自己,當成prototype(原型)。當父類看到這些原型的時候,就以此為藍本建立

寫程式碼的時候,先寫type name,再寫object name,可是畫圖的時候剛好相反,如圖:

建立原型:

整體

TIP: 如果我們讓clone是一個靜態函式,這樣不需要原型也可以調得到,但是靜態函式的呼叫一定要用class name,所以此方法行不通。

Class本體的static型別的data。一定要在class外面定義,如下圖所示: