C++ 面向对象(四)—— 多态 (Polymorphism)
基類的指針(Pointers to base class)
繼承的好處之一是一個指向子類(derived class)的指針與一個指向基類(base class)的指針是type-compatible的。?本節就是重點介紹如何利用C++的這一重要特性。例如,我們將結合C++的這個功能,重寫前面小節中關于長方形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 |
在主函數 main 中定義了兩個指向class CPolygon的對象的指針,即 *ppoly1 和 *ppoly2。 它們被賦值為rect 和 trgl的地址,因為rect 和 trgl是CPolygon 的子類的對象,因此這種賦值是有效的。
使用*ppoly1 和 *ppoly2 取代rect 和trgl 的唯一限制是*ppoly1 和 *ppoly2 是CPolygon* 類型的,因此我們只能夠引用CRectangle 和 CTriangle 從基類CPolygon中繼承的成員。正是由于這個原因,我們不能夠使用*ppoly1 和 *ppoly2 來調用成員函數 area(),而只能使用rect 和 trgl來調用這個函數。
要想使CPolygon 的指針承認area()為合法成員函數,必須在基類中聲明它,而不能只在子類進行聲明(見下一小節)。
?
虛擬成員(Virtual members)
如果想在基類中定義一個成員留待子類中進行細化,我們必須在它前面加關鍵字virtual ,以便可以使用指針對指向相應的對象進行操作。
請看一下例子:
| // 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 |
現在這三個類(CPolygon, CRectangle 和 CTriangle) 都有同樣的成員:width, height, set_values() 和 area()。
area() 被定義為virtual 是因為它后來在子類中被細化了。你可以做一個試驗,如果在代碼種去掉這個關鍵字(virtual),然后再執行這個程序,三個多邊形的面積計算結果都將是 0 而不是20,10,0。這是因為沒有了關鍵字virtual ,程序執行不再根據實際對象的不用而調用相應area() 函數(即分別為CRectangle::area(), CTriangle::area() 和 CPolygon::area()),取而代之,程序將全部調用CPolygon::area(),因為這些調用是通過CPolygon類型的指針進行的。
因此,關鍵字virtual 的作用就是在當使用基類的指針的時候,使子類中與基類同名的成員在適當的時候被調用,如前面例子中所示。
注意,雖然本身被定義為虛擬類型,我們還是可以聲明一個CPolygon 類型的對象并調用它的area() 函數,它將返回0 ,如前面例子結果所示。
?
抽象基類(Abstract base classes)
基本的抽象類與我們前面例子中的類CPolygon 非常相似,唯一的區別是在我們前面的例子中,我們已經為類CPolygon的對象(例如對象poly)定義了一個有效地area()函數,而在一個抽象類(abstract base class)中,我們可以對它不定義,而簡單得在函數聲明后面寫 =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 來代替函數的具體實現的。這種函數被稱為純虛擬函數(pure virtual function),而所有包含純虛擬函數的類被稱為抽象基類(abstract base classes)。
抽象基類的最大不同是它不能夠有實例(對象),但我們可以定義指向它的指針。因此,像這樣的聲明:
CPolygon poly;
對于前面定義的抽象基類是不合法的。
然而,指針:
CPolygon * ppoly1;
CPolygon * ppoly2
是完全合法的。這是因為該類包含的純虛擬函數(pure virtual function) 是沒有被實現的,而又不可能生成一個不包含它的所有成員定義的對象。然而,因為這個函數在其子類中被完整的定義了,所以生成一個指向其子類的對象的指針是完全合法的。
下面是完整的例子:
| // 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 |
再看一遍這段程序,你會發現我們可以用同一種類型的指針(CPolygon*)指向不同類的對象,至一點非常有用。 想象一下,現在我們可以寫一個CPolygon 的成員函數,使得它可以將函數area()的結果打印到屏幕上,而不必考慮具體是為哪一個子類。
| // 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 代表代碼正在被執行的這一個對象的指針。
抽象類和虛擬成員賦予了C++ 多態(polymorphic)的特征,使得面向對象的編程object-oriented programming成為一個有用的工具。這里只是展示了這些功能最簡單的用途。想象一下如果在對象數組或動態分配的對象上使用這些功能,將會節省多少麻煩
總結
以上是生活随笔為你收集整理的C++ 面向对象(四)—— 多态 (Polymorphism)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 背景建模算法比较与ViBe算法论文解读与
- 下一篇: uniapp 使用 colorUI