C 三大特性之多型(詳細)

2021-09-24 22:31:19 字數 4490 閱讀 7739

c++特性詳解

c++分為三大特性:_封裝、_繼承、_多型

_封裝: 類是物件導向程式設計語言中的乙個概念。類是對某個物件的定義。包含有關物件動作方式的資訊,包括它的名稱、方法、屬性和事件。

封裝的類有如下的訪問型別:

1)公有( public )成員可以在類外訪問;   2)私有( private )成員只能被該類的成員函式訪問; 

3)保護( protected )成員只能被該類的成員函式或派生類的成員函式訪問。

資料成員通常是私有的,成員函式通常有一部分是公有的,一部分是私有的。因為類的公有的函式可以在類外被訪問,也稱之為類的介面。(實際中具體的訪問許可權情況根據實際情況而定)

網上查到的封裝的有點: 程式更模組化,更易讀易寫,提公升了**重用到乙個更高的層次。其實我認為更重要的是保密性和跨平台性。

[x]封裝成dll動態鏈結庫後也可以實現程式的保密性(需要提供專案**時,部分核心演算法可以封裝起來!)

[x]同時乙個vber使用他的vb程式呼叫你的c++演算法時,通過c++封裝成dll可以實現跨平台性的使用。(反過來呼叫比較麻煩,參考com元件的使用)

值得注意的是類的封裝要滿足單一職責原則,只完成單獨的使命,萬萬不可塗一時之快,寫成了武林全集的dll,後期維護就很頭疼了。

_繼承:物件導向程式設計中最重要的乙個概念是繼承。繼承允許我們依據另乙個類來定義乙個類,這使得建立和維護乙個應用程式變得更容易。

這樣做,也達到了重用**功能和提高執行時間的效果。當建立乙個類時,您不需要重新編寫新的資料成員和成員函式,只需指定新建的類繼承了乙個已有的類的成員即可。

這個已有的類稱為基類,新建的類稱為派生類。例如,定義車是基類,那麼派生類可以是大眾或者是賓士,等等。

_多型:顧名思義就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多型。

c++ 多型意味著呼叫成員函式時,會根據呼叫函式的物件的型別來執行不同的函式。

先看一段程式引用:

class base  };

class derived : public base  };

int main()

輸出結果:

基類函式呼叫

基類函式呼叫

上述程式中,可以看出派生類中沒有testfunc()函式,所以呼叫的為基類的testfunc()函式;接下來我們將注釋去掉再看看效果會怎麼樣

class base  };

class derived : public base  };

int main()

輸出結果:

基類函式呼叫

派生類函式呼叫

基類函式呼叫

根據上面的輸出,可以看出來派生類雖然繼承了基類的testfunc()函式但是派生類本身中testfunc()函式,此時構成了重定義,即基類中的testfunc()函式被隱藏,因此呼叫的是派生類的testfunc()函式

當然可以根據 d.base::testfunc()來獲取基類的成員函式

接下來保持上面的類定義不變,我們試試用指標來呼叫實現

class base  };

class derived : public base  };

int main()

輸出結果:

基類函式呼叫

派生類函式呼叫

基類函式呼叫

基類函式呼叫

派生類函式呼叫

基類函式呼叫

在上面的**如果我們在基類的fun函式前加virtual即可實現動態繫結:

class base  };

class derived : public base  };

int main()

輸出結果:

基類函式呼叫

派生類函式呼叫

派生類函式呼叫

基類函式呼叫

派生類函式呼叫

派生類函式呼叫

我們知道,c++繼承中有賦值相容,即基類指標可以指向子類,那麼為什麼還會出現基類指標指向子類或者基類物件引用子類物件,卻呼叫基類自己的testfunc()函式呢?

這就是靜態聯編,在編譯時期就將函式實現和函式呼叫關聯起來,不管是引用還是指標在編譯時期都是base類的自然呼叫base類的testfunc()。為了避免這種情況,我們引入了動態多型。 所謂的動態多型是通過繼承+虛函式來實現的,只有在程式執行期間(非編譯期)才能判斷所引用物件的實際型別,根據其實際型別呼叫相應的方法。具體格式就是使用virtual關鍵字修飾類的成員函式時,指明該函式為虛函式,並且派生類需要重新實現該成員函式,編譯器將實現動態繫結。

聯編是指乙個程式自身彼此關聯的過程。按照聯編所進行的階段不同,可分為靜態聯編和動態聯編。

靜態聯編又稱靜態繫結,指在呼叫同名函式(即過載函式)時編譯器將根據呼叫時所使用的實參在編譯時就確定下來應該呼叫的函式實現。它是在程式編譯連線階段進行聯編的,這種聯編又稱為早期聯編,這是因為這種聯編工作是在程式執行之前完成的。它的優點是速度快,效率高,但靈活性不夠。編譯時所進行的聯編又稱為靜態束定。束定是指確定所呼叫的函式與執行該函式**之間的關係。

動態聯編也稱動態繫結,是指在程式執行時,根據當時的情況來確定呼叫的同名函式的實現,實際上就是在執行時選擇虛函式的實現。這種聯編又稱為晚期聯編或動態(束定。實現條件:①要有繼承性且要求建立子型別關係;)②要有虛函式;③通過基類的物件指標或引用訪問虛函式。繼承是動態聯編的基礎,虛函式是動態聯編的關鍵,虛函式經過派生之後,在類族中就可以實現執行過程中的多型。動態聯編要求在執行時解決程式中的函式呼叫與執行該函式**間的關係,呼叫虛函式的物件是在執行時確定的。對於同乙個物件的引用,採用不同的聯編方式將會被聯編到不同類的物件上。即不同聯編可以選擇不同的實現,這便是多型性。它的優點是靈活性強,但效率較低。 

聯編說白了就是為了滿足實際機制,特別設計出來的乙個語法規則!!!

或者我們可以將主函式這麼寫(精簡寫法):

class base  };

class derived : public base  };

int main()

輸出結果:

基類函式呼叫

class base  };

class derived : public base  };

int main()

輸出結果:

派生類函式呼叫

注意上訴兩個程式的區別,前者沒有virtual()函式

父類子類指標函式呼叫注意事項

1,如果以乙個基礎類指標指向乙個衍生類物件(派生類物件),那麼經由該指標只能訪問基礎類定義的函式(靜態聯翩)

2,如果以乙個衍生類指標指向乙個基礎類物件,必須先做強制轉型動作(explicit cast),這種做法很危險,也不符合生活習慣,在程式設計上也會給程式設計師帶來困擾。(一般不會這麼去定義)

3,如果基礎類和衍生類定義了相同名稱的成員函式,那麼通過物件指標呼叫成員函式時,到底呼叫那個函式要根據指標的原型來確定,而不是根據指標實際指向的物件型別確定。

另外補充一點:

我們知道c++中虛函式允許子類重新定義成員函式,而子類重新定義父類的做法稱為覆蓋(override),或者稱為重寫。在這裡我覺得有必要要明白幾個概念的區別:即過載,重寫(覆蓋),以及重定義(同名隱藏)。 

過載:指在同一作用域中允許有多個同名函式,而這些函式的引數列表不同,包括引數個數不同,型別不同,次序不同,需要注意的是返回值相同與否並不影響是否過載。

重寫(覆蓋)和重定義(同名隱藏)則有點像,區別就是在寫重寫的函式是否是虛函式,只有重寫了虛函式的才能算作是體現了c++多型性,否則即為重定義,在之前的**中,我們看到子類繼承了基類的函式,若是子類(派生類)沒有函式,依舊會呼叫基類的函式,若是子類已重定義,則呼叫自己的函式,這就叫做同名隱藏。

(當然此時如果還想呼叫基類的testfunc函式,只需在呼叫testfunc函式前加基類和作用域限定符即可)

綜上他們的關係和區別如下圖表明:

虛函式虛函式 是在基類中使用關鍵字 virtual 宣告的函式。在派生類中重新定義基類中定義的虛函式時,會告訴編譯器不要靜態鏈結到該函式。

我們想要的是在程式中任意點可以根據所呼叫的物件型別來選擇呼叫的函式,這種操作被稱為動態鏈結,或後期繫結。

純虛函式

您可能想要在基類中定義虛函式,以便在派生類中重新定義該函式更好地適用於物件,但是您在基類中又不能對虛函式給出有意義的實現,這個時候就會用到純虛函式。

我們可以把基類中的虛函式 area() 改寫如下:

class shape // pure virtual function

virtual int area() = 0;

};= 0 告訴編譯器,函式沒有主體,上面的虛函式是純虛函式。

值得注意的是,純虛函式不能例項化,只是用來給子類提供便利的;

C 三大特性之多型

c 的三大特性,封裝,繼承,多型。封裝可以使得 模組化,繼承可以擴充套件已存在的 而多型的目的則是為了介面重用。本篇部落格主要介紹c 中多型的相關概念及使用方法。多型性是允許你將父物件設定成為和乙個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡...

三大特性之 多型

乙個行為不同的物件產生出不同的形態這就是多型,多型也是實現 復用的方式那麼為什麼呢?為什麼多型也是 復用的產物呢,因為多型的第乙個前提就是繼承,必須建立在繼承的基礎之上,才有多型之談,也就是說這個不同的物件也是有前提的,就是在繼承的條件之下的不同的類物件,簡單來說就是子類和基類 多型的第乙個條件就是...

java三大特性之多型

多型 多型的概述 1 多型 事物的多種狀態,polymorphic 物件的多型性 同乙個物件,可能具有不同的名稱,同乙個物件,有不同的型別的引用指向它。本質 同乙個物體有不同的名稱和描述。型別的多型性 同乙個型別,可能具有不同的子類實現。同乙個型別引用,有不同的物件實現。本質 同乙個名字和描述,可以...