實實在在說多型(c++篇)
1. 什麼是多型... 1
2. 多型帶來的好處... 1
3. c++中實現多型的方式... 1
4. 細說用函式過載實現的多型... 2
5. 細說用模板函式實現的多型... 3
6. 小結... 4
7. 細說用虛函式實現的多型... 4
7.1.
虛函式是怎麼回事... 4
7.2.
向上轉型... 5
7.3.
為什麼要用指標或引用來實現動態多型... 6
7.4.
為什麼動態多型要用public繼承... 6
8. 總結... 7
9. 附錄:... 7
1. 什麼是多型
多型是c++中的乙個重要的基礎,可以這樣說,不掌握多型就是c++的門外漢。然而長期以來,c++社群對於多型的內涵和外延一直爭論不休。大有只見樹木不見森林之勢。多型到底是怎麼回事呢?說實在的,我覺的多型這個名字起的不怎麼好(或是譯的不怎麼好)。要是我給起名的話,我就給它定乙個這樣的名字--「呼叫』同名函式』卻會因上下文不同會有不同的實現的一種機制」。這個名字長是長了點兒,可是比「多型」清楚多了。看這個長的定義,我們可以從中找出多型的三個重要的部分。一是「相同函式名」,二是「依據上下文」,三是「實現卻不同」。嘿,還是個順口溜呢。我們且把它們叫做多型三要素吧。
2. 多型帶來的好處
多型帶來兩個明顯的好處:一是不用記大量的函式名了,二是它會依據呼叫時的上下文來確定實現。確定實現的過程由c++本身完成另外還有乙個不明顯但卻很重要的好處是:帶來了物件導向的程式設計。
3. c++中實現多型的方式
c++中共有三種實現多型的方式。由「容易說明白」到「不容易說明白」排序分別為。第一種是函式過載;第二種是模板函式;第三種是虛函式。
4. 細說用函式過載實現的多型
函式過載是這樣一種機制:允許有不同引數的函式有相同的名字。
具體一點講就是:假如有如下三個函式:
void test(int arg){}
//函式1
void test(char arg){}
//函式2
void test(int arg1,int arg2){}
//函式3
如果在c中編譯,將會得到乙個名字衝突的錯誤而不能編譯通過。在c++中這樣做是合法的。可是當我們呼叫test的時候到底是會呼叫上面三個函式中的哪乙個呢?這要依據你在呼叫時給的出的引數來決定。如下:
test(5);
//呼叫函式1
test('c');//呼叫函式2
test(4,5); //呼叫函式3
c++是如何做到這一點的呢?原來聰明的c++編譯器在編譯的時候悄悄的在我們的函式名上根據函式的引數的不同做了一些不同的記號。具體說如下:
void test(int arg)
//被標記為 『test有乙個int型引數』
void test(char arg)
//被標記為 『test有乙個char型的引數』
void test(int arg1,int arg2) //被標記為 『test第乙個引數是int型,第二個引數為int型』
這樣一來當我們進行對test的呼叫時,c++就可以根據呼叫時的引數來確定到底該用哪乙個test函式了。噢,聰明的c++編譯器。其實c++做標記做的比我上面所做的更聰明。我上面哪樣的標記太長了。c++編譯器用的標記要比我的短小的多。看看這個真正的c++的對這三個函式的標記:
?test@@yaxd@z
?test@@yaxh@z
?test@@yaxhh@z
是不是短多了。但卻不好看明白了。好在這是給計算機看的,人看不大明白是可以理解的。
還記得cout吧。我們用《可以讓它把任意型別的資料輸出。比如可以象下面那樣:
cout << 1;
//輸出int型
cout << 8.9; //輸出double型
cout << 'a';
//輸出char型
cout << "abc";//輸出char陣列型
cout << endl; //輸出乙個函式
cout之所以能夠用乙個函式名<<(《是乙個函式名)就能做到這些全是函式過載的功能。要是沒有函式過載,我們也許會這樣使用cout,如下:
cout int<< 1;
//輸出int型
cout double<< 8.9;
//輸出double型
cout char<< 'a';
//輸出char型
cout chararray<< "abc";
//輸出char陣列型
cout function(…)<< endl;
//輸出函式
為每一種要輸出的型別起乙個函式名,這豈不是很麻煩呀。
不過函式過載有乙個美中不足之處就是不能為返回值不同的函式進行過載。那是因為人們常常不為函式呼叫指出返回值。並不是技術上不能通過返回值來進行過載。
5. 細說用模板函式實現的多型
所謂模板函式(也有人叫函式模板)是這樣乙個概念:函式的內容有了,但函式的引數型別卻是待定的(注意:引數個數不是待定的)。比如說乙個(準確的說是一類或一群)函式帶有兩個引數,它的功能是返回其中的大值。這樣的函式用模板函式來實現是適合不過的了。如下。
template < typename t>
t getmax(t arg1, t arg2)
這就是基於模板的多型嗎?不是。因為現在我們不論是呼叫getmax(1, 2)還是呼叫getmax(3.0, 5.0)都是走的上面的函式定義。它沒有根據呼叫時的上下文不同而執行不同的實現。所以這充其量也就是用了乙個模板函式,和多型不沾邊。怎樣才能和多型沾上邊呢?用模板特化呀!象這樣:
template<>
char* getmax(char* arg1, char* arg2)
這樣一來當我們呼叫getmax(「abc」, 「efg」)的時候,就會執行**段2,而不是**段1。這樣就是多型了。
更有意思的是如果我們再寫這樣乙個函式:
char getmax(char arg1, char arg2)
C 多型三種實現方式
定義 多型的定義簡單來說就是使一條語句有多種狀態。實現方式 多型的實現方式分為三塊 過載 重寫 重定義。下面我們來談一談他們各自的實現方式和實現原理。過載實現方式 過載是在同一作用域內 不管是模組內還是類內,只要是在同一作用域內 具有相同函式名,不同的形參個數或者形參型別。返回值可以相同也可以不同 ...
C 多型的三種實現方式 小結
c 實現多型主要有3種方法,虛方法,抽象類,介面 在父類的方法前面加關鍵字virtual,子類重寫該方法時在方法名前面加上override關鍵字,例如下面的person類的sayhello方法 class p程式設計客棧erson string name public string name 父類方...
c 多型實現的方式
1.多型概念 讓乙個物件能夠表現出多種狀態 型別 實現多型的條件 類必須具有繼承。2.實現多型的三種方法 1 虛方法 2 抽象類 3 介面 步驟 1 在父類的返回型別前加virtual 表示成虛方法 2 在子類的返回型別前加override,表示將父類的方法重新寫一遍。per i sayhello ...