C++ 面向对象(四)—— 多态 (Polymorphism)
基類的指針(Pointers to base class)
繼承的好處之一是一個指向子類(derived class)的指針與一個指向基類(base class)的指針是type-compatible的。?本節(jié)就是重點(diǎn)介紹如何利用C++的這一重要特性。例如,我們將結(jié)合C++的這個功能,重寫前面小節(jié)中關(guān)于長方形rectangle 和三角形 triangle 的程序:
| // pointers to base class #include <iostream.h> class CPolygon { protected:int width, height; public:void set_values (int a, int b) {width=a; height=b;} }; class CRectangle: public CPolygon { public:int area (void) {return (width * height);} }; class CTriangle: public CPolygon { public:int area (void) {return (width * height / 2);} }; int main () {CRectangle rect;CTriangle trgl;CPolygon * ppoly1 = ▭CPolygon * ppoly2 = &trgl;ppoly1->set_values (4,5);ppoly2->set_values (4,5);cout << rect.area() << endl;cout << trgl.area() << endl;return 0; } | 20 10 |
在主函數(shù) main 中定義了兩個指向class CPolygon的對象的指針,即 *ppoly1 和 *ppoly2。 它們被賦值為rect 和 trgl的地址,因為rect 和 trgl是CPolygon 的子類的對象,因此這種賦值是有效的。
使用*ppoly1 和 *ppoly2 取代rect 和trgl 的唯一限制是*ppoly1 和 *ppoly2 是CPolygon* 類型的,因此我們只能夠引用CRectangle 和 CTriangle 從基類CPolygon中繼承的成員。正是由于這個原因,我們不能夠使用*ppoly1 和 *ppoly2 來調(diào)用成員函數(shù) area(),而只能使用rect 和 trgl來調(diào)用這個函數(shù)。
要想使CPolygon 的指針承認(rèn)area()為合法成員函數(shù),必須在基類中聲明它,而不能只在子類進(jìn)行聲明(見下一小節(jié))。
?
虛擬成員(Virtual members)
如果想在基類中定義一個成員留待子類中進(jìn)行細(xì)化,我們必須在它前面加關(guān)鍵字virtual ,以便可以使用指針對指向相應(yīng)的對象進(jìn)行操作。
請看一下例子:
| // virtual members #include <iostream.h> class CPolygon {protected:int width, height;public:void set_values (int a, int b) {width=a;height=b;}virtual int area (void) { return (0); } }; class CRectangle: public CPolygon {public:int area (void) { return (width * height); } }; class CTriangle: public CPolygon {public:int area (void) {return (width * height / 2);} }; int main () {CRectangle rect;CTriangle trgl;CPolygon poly;CPolygon * ppoly1 = ▭CPolygon * ppoly2 = &trgl;CPolygon * ppoly3 = &poly;ppoly1->set_values (4,5);ppoly2->set_values (4,5);ppoly3->set_values (4,5);cout << ppoly1->area() << endl;cout << ppoly2->area() << endl;cout << ppoly3->area() << endl;return 0; } | 20 10 0 |
現(xiàn)在這三個類(CPolygon, CRectangle 和 CTriangle) 都有同樣的成員:width, height, set_values() 和 area()。
area() 被定義為virtual 是因為它后來在子類中被細(xì)化了。你可以做一個試驗,如果在代碼種去掉這個關(guān)鍵字(virtual),然后再執(zhí)行這個程序,三個多邊形的面積計算結(jié)果都將是 0 而不是20,10,0。這是因為沒有了關(guān)鍵字virtual ,程序執(zhí)行不再根據(jù)實際對象的不用而調(diào)用相應(yīng)area() 函數(shù)(即分別為CRectangle::area(), CTriangle::area() 和 CPolygon::area()),取而代之,程序?qū)⑷空{(diào)用CPolygon::area(),因為這些調(diào)用是通過CPolygon類型的指針進(jìn)行的。
因此,關(guān)鍵字virtual 的作用就是在當(dāng)使用基類的指針的時候,使子類中與基類同名的成員在適當(dāng)?shù)臅r候被調(diào)用,如前面例子中所示。
注意,雖然本身被定義為虛擬類型,我們還是可以聲明一個CPolygon 類型的對象并調(diào)用它的area() 函數(shù),它將返回0 ,如前面例子結(jié)果所示。
?
抽象基類(Abstract base classes)
基本的抽象類與我們前面例子中的類CPolygon 非常相似,唯一的區(qū)別是在我們前面的例子中,我們已經(jīng)為類CPolygon的對象(例如對象poly)定義了一個有效地area()函數(shù),而在一個抽象類(abstract base class)中,我們可以對它不定義,而簡單得在函數(shù)聲明后面寫 =0 (等于0)。
類CPolygon 可以寫成這樣:
// abstract class CPolygon class CPolygon {protected:int width, height;public:void set_values (int a, int b) {width=a;height=b;}virtual int area (void) =0; };注意我們是如何在virtual int area (void)加 =0 來代替函數(shù)的具體實現(xiàn)的。這種函數(shù)被稱為純虛擬函數(shù)(pure virtual function),而所有包含純虛擬函數(shù)的類被稱為抽象基類(abstract base classes)。
抽象基類的最大不同是它不能夠有實例(對象),但我們可以定義指向它的指針。因此,像這樣的聲明:
CPolygon poly;
對于前面定義的抽象基類是不合法的。
然而,指針:
CPolygon * ppoly1;
CPolygon * ppoly2
是完全合法的。這是因為該類包含的純虛擬函數(shù)(pure virtual function) 是沒有被實現(xiàn)的,而又不可能生成一個不包含它的所有成員定義的對象。然而,因為這個函數(shù)在其子類中被完整的定義了,所以生成一個指向其子類的對象的指針是完全合法的。
下面是完整的例子:
| // virtual members #include <iostream.h> class CPolygon {protected:int width, height;public:void set_values (int a, int b) {width=a;height=b;}virtual int area (void) =0; }; class CRectangle: public CPolygon {public:int area (void) { return (width * height); } }; class CTriangle: public CPolygon {public:int area (void) {return (width * height / 2);} }; int main () {CRectangle rect;CTriangle trgl;CPolygon * ppoly1 = ▭CPolygon * ppoly2 = &trgl;ppoly1->set_values (4,5);ppoly2->set_values (4,5);cout << ppoly1->area() << endl;cout << ppoly2->area() << endl;return 0; } | 20 10 |
再看一遍這段程序,你會發(fā)現(xiàn)我們可以用同一種類型的指針(CPolygon*)指向不同類的對象,至一點(diǎn)非常有用。 想象一下,現(xiàn)在我們可以寫一個CPolygon 的成員函數(shù),使得它可以將函數(shù)area()的結(jié)果打印到屏幕上,而不必考慮具體是為哪一個子類。
| // virtual members #include <iostream.h> class CPolygon {protected:int width, height;public:void set_values (int a, int b) {width=a;height=b;}virtual int area (void) =0;void printarea (void) {cout << this->area() << endl;} }; class CRectangle: public CPolygon {public:int area (void) { return (width * height); } }; class CTriangle: public CPolygon {public:int area (void) {return (width * height / 2);} }; int main () {CRectangle rect;CTriangle trgl;CPolygon * ppoly1 = ▭CPolygon * ppoly2 = &trgl;ppoly1->set_values (4,5);ppoly2->set_values (4,5);ppoly1->printarea();ppoly2->printarea();return 0; } | 20 10 |
記住,this 代表代碼正在被執(zhí)行的這一個對象的指針。
抽象類和虛擬成員賦予了C++ 多態(tài)(polymorphic)的特征,使得面向?qū)ο蟮木幊蘯bject-oriented programming成為一個有用的工具。這里只是展示了這些功能最簡單的用途。想象一下如果在對象數(shù)組或動態(tài)分配的對象上使用這些功能,將會節(jié)省多少麻煩
總結(jié)
以上是生活随笔為你收集整理的C++ 面向对象(四)—— 多态 (Polymorphism)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 背景建模算法比较与ViBe算法论文解读与
- 下一篇: C++ 高级数据类型(六)—— 自定义数