c++中,實現多型有以下方法:虛函式,抽象類,過載,覆蓋
多型性在object pascal和c++中都是通過虛函式(virtual function) 實現的。
這麼一大堆名詞,實際上就圍繞一件事展開,就是多型,其他三個名詞都是為實現c++的多型機制而提出的一些規則,下面分兩部分介紹,第一部分介紹【多型】,第二部分介紹【虛函式,純虛函式,抽象類】
一 【多型】
多型的概念:關於多型,好幾種說法,好的壞的都有,分別說一下:
1 指同乙個函式的多種形態。
個人認為這是一種高手中的高手喜歡的說法,對於一般開發人員是一種差的不能再差的概念,簡直是對人的誤導,然人很容易就靠到函式過載上了。
以下是個人認為解釋的比較好的兩種說法,意思大體相同:
2多型是具有表現多種形態的能力的特徵,在oo中是指,語言具有根據物件的型別以不同方式處理之,特別是過載方法和繼承類這種形式的能力。
這種說法有點繞,仔細想想,這才是c++要告訴我們的。
3多型性是允許你將父物件設定成為和乙個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。多型性在object pascal和c++中都是通過虛函式(virtual function) 實現的。
這種說法看來是又易懂,又全面的一種,尤其是最後一句,直接點出了虛函式與多型性的關係,如果你還是不太懂,沒關係,再把3讀兩遍,有個印象,往後看吧。
二 【虛函式,純虛函式,抽象類】
多型才說了個概念,有什麼用還沒說就進入第二部分了?看看概念3的最後一句,虛函式就是為多型而生的,多型的作用的介紹和虛函式簡直關係太大了,就放一起說吧。
多型的作用:繼承是子類使用父類的方法,而多型則是父類使用子類的方法。這是一句大白話,多型從用法上就是要用父類(確切的說是父類的物件名)去呼叫子類的方法,例如:
【例一】
class a
(virtual) void print()
};class b : public a
void print()
};int main(int argc, char* argv)
這將顯示:
this is b.
如果把virtual去掉,將顯示:
this is a.
(make1,2,3分別是對應相容規則(後面介紹)的三種方式,呼叫結果是一樣的)
加上virtual ,多型了,b中的print被呼叫了,也就是可以實現父類使用子類的方法。
對多型的作用有乙個初步的認識了之後,再提出更官方,也是更準確的對多型作用的描述:
多型性使得能夠利用同一類(基類)型別的指標來引用不同類的物件,以及根據所引用物件的不同,以不同的方式執行相同的操作。把不同的子類物件都當作父類來看,可以遮蔽不同子類物件之間的差異,寫出通用的**,做出通用的程式設計,以適應需求的不斷變化。賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作(也就是可以呼叫子物件中對父物件的相關函式的改進方法)。
那麼上面例子中為什麼去掉virtual就呼叫的不是b中的方法了呢,明明把b的物件賦給指標a了啊,是因為c++定義了一組物件賦值的相容規則,就是指在公有派生的情況下,對於某些場合,乙個派生類的物件可以作為基類物件來使用,具體來說,就是下面三種情形:
class a ;
class b:public a
1. 派生的物件可以賦給基類的物件
a a;
b b;
a = b;
2. 派生的物件可以初始化基類的引用
b b;
a &a = b;
3. 派生的物件的位址可以賦給指向基類的指標
b b;
a *a = &b;
或a *a = new b();
由上述物件賦值相容規則可知,乙個基類的物件可相容派生類的物件,乙個基類的指標可指向派生類的物件,乙個基類的引用可引用派生類的物件,於是對於通過基類的物件指標(或引用)對成員函式的呼叫,編譯時無法確定物件的類,而只是在執行時才能確定並由此確定呼叫哪個類中的成員函式。
看看剛才的例子,根據相容規則,b的物件根本就被當成了a的物件來使用,難怪b的方法不能被呼叫。
【例二】
#include
using namespace std;
class a
public:
void (virtual) print()
float print()
private:
class c : public a
public:
c(float h0,float w0)
float print()
private:
int main(void)
a *a1,*a2;
b b(1,2);
c c(1,2);
a1 = &b;
a2 = &c;
cout << a1->print()<<","return 0;
結果為:
2,1在這個例子中,a就是乙個抽象類,基類a中print沒有確定具體的操作,但不能從基類中去掉,否則不能使用基類的指標a1,a2呼叫派生類中的方法(a1->print;a2->print就不能用了),給多型性造成不便,這裡要強調的是,我們是希望用基類的指標呼叫派生類的方法,希望用到多型機制,如果讀者並不想用基類指標,認為用b,c指標直接呼叫更好,那純虛函式就沒有意義了,多型也就沒有意義了,了解一下多型的好處,再決定是否用純虛函式吧。
【注意】
1 抽象類並不能直接定義物件,只可以如上例那樣宣告指標,用來指向基類派生的子類的物件,上例中的a *a1,*a2;該為 a a1,a2;是錯誤的。
2 從乙個抽象類派生的類必須提供純虛函式的**實現或依舊指明其為派生類,否則是錯誤的。
3 當乙個類打算被用作其它類的基類時,它的析構函式必須是虛的。
【例三】
class a
~a() // 非虛析構函式
private:
char * ptra_;
};class b: public a
~b()
private:
char * ptrb_;
};void foo()
在這個例子中,程式也許不會象你想象的那樣執行,在執行delete a的時候,實際上只有a::~a()被呼叫了,而b類的析構函式並沒有被呼叫!這是否有點兒可怕? 如果將上面a::~a()改為virtual,就可以保證b::~b()也在delete a的時候被呼叫了。因此基類的析構函式都必須是virtual的。純虛的析構函式並沒有什麼作用,是虛的就夠了。通常只有在希望將乙個類變成抽象類(不能例項化的類),而這個類又沒有合適的函式可以被純虛化的時候,可以使用純虛的析構函式來達到目的。
最後通過乙個例子說明一下抽象類,純虛函式以及多型的妙用吧:
我們希望通過乙個方法得到不同圖形面積的和的方式:
#include
using namespace std;
class a //定義乙個抽象類,用來求圖形面積
public:
virtual float area() = 0;//定義乙個計算面積的純虛函式,圖形沒確定,當
//不能確定具體實現
protected:
float h,w; //這裡假設所有圖形的面積都可以用h和w兩個元素計算得出
//就假設為高和長吧
private:
class b : public a //定義乙個求長方形面積的類
public:
b(float h0,float w0)
float area ()//基類純虛函式的具體實現
private:
class c : public a //定義乙個求三角形面積的類
public:
c(float h0,float w0)
float area ()//基類純虛函式的具體實現
private:
float gettotal(a *s,int n)//通過乙個陣列傳遞所有的圖形物件
//多型的好處出來了吧,不是多型,不能用基類a呼叫
//引數型別怎麼寫,要是有100個不同的圖形,怎麼傳遞
float sum = 0;
for(int i = 0;i < n; i++)
sum = sum + s[i]->area();
return sum;
int main(void)
float totalarea;
a *a[2];
a[0] = new b(1,2); //乙個長方形物件
a[1] = new c(1,2);//乙個三角形物件
totalarea = gettotal(a , 2);//求出兩個物件的面積和
getchar();
return 0;
虛函式,純虛函式,抽象類
1 虛函式 include includeusing namespace std class animal 執行結果 2 純虛函式 抽象類 include includeusing namespace std class animal class mouse public animal void c...
抽象類 純虛函式 虛函式
抽象類是一種特殊的類,它是為了抽象和設計的目的為建立的,它處於繼承層次結構的較上層。1 抽象類的定義 稱帶有純虛函式的類為抽象類。2 抽象類的作用 抽象類的主要作用是將有關的操作作為結果介面組織在乙個繼承層次結構中,由它來為派生類提供乙個公共的根,也就是說抽象類是為派生類服務的。純虛函式作為基類中的...
多型 虛函式 虛析構函式 純虛函式和抽象類
一 多型 只對指標和引用有用 1 定義 多型是指當基類的指標 或引用 繫結到派生類物件上,通過此指標 或引用 呼叫基類的成員函式時,實際上呼叫到的是該函式在派生類中的覆蓋函式版本。2 多型的兩種表現形式 其實如果乙個基類中的乙個函式為虛函式的話,若其派生類中有同名的函式,但是沒有標明為虛函式的話,預...