Latest web development tutorials

C++ 多態

多態按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多態。

C++ 多態意味著調用成員函數時,會根據調用函數的對象的類型來執行不同的函數。

下面的實例中,基類Shape 被派生為兩個類,如下所示:

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程序的主函数
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // 存储矩形的地址
   shape = &rec;
   // 调用矩形的求面积函数 area
   shape->area();

   // 存储三角形的地址
   shape = &tri;
   // 调用三角形的求面积函数 area
   shape->area();
   
   return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Parent class area
Parent class area

導致錯誤輸出的原因是,調用函數area()被編譯器設置為基類中的版本,這就是所謂的靜態多態 ,或靜態鏈接 -函數調用在程序執行前就準備好了。 有時候這也被稱為早綁定 ,因為area()函數在程序編譯期間就已經設置好了。

但現在,讓我們對程序稍作修改,在Shape類中,area()的聲明前放置關鍵字virtual ,如下所示:

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

修改後,當編譯和執行前面的實例代碼時,它會產生以下結果:

Rectangle class area
Triangle class area

此時,編譯器看的是指針的內容,而不是它的類型。 因此,由於tri 和rec 類的對象的地址存儲在*shape 中,所以會調用各自的area() 函數。

正如您所看到的,每個子類都有一個函數area() 的獨立實現。 這就是多態的一般使用方式。 有了多態,您可以有多個不同的類,都帶有同一個名稱但具有不同實現的函數,函數的參數甚至可以是相同的。

虛函數

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

我們想要的是在程序中任意點可以根據所調用的對像類型來選擇調用的函數,這種操作被稱為動態鏈接 ,或後期綁定

純虛函數

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

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

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      // pure virtual function
      virtual int area() = 0;
};

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