1. 程式人生 > >C++ 多型性有哪些

C++ 多型性有哪些

C++多型性有哪些? 概念:指相同的物件收到不同的訊息或者不同的物件收到相同的訊息時產生的不同的實現動作。 C++支援兩種多型:編譯時多型(靜態)、執行時多型(動態) (1)編譯時多型:就是在編譯期確定的一種多型。在C++中主要體現在函式模板,這裡需要注意,函式過載和多型無關,很多地方把函式過載誤認為是編譯多型,這是錯誤的???      舉例說明一下函式模板是如何體現多型的:
//例1 函式模板體現編譯期多型性
#include <iostream>
using namespace std;

template <typename T>
T add(T a, T b)
{
     t c = a+b;
     return c;
}

int main()
{
     int a1 = 1;
     int b1 = 2;
     int c1 = add(a1,b1);
     cout<<"c1:"<<c1<<endl;
     
     double a2 = 2.0;
     double b2 = 4.0;
     double c2 = add(a2,b2);
     cout<<"c2:"<<c2<<endl;
}
在例1中,我們定義了一個函式模板,用來計算兩個數的和。這兩個數的資料型別在使用時才知道,main函式中呼叫同一個函式分別計算了兩個int值和兩個double值的和,這就體現了多型,在編譯期,編譯器根據一定的最佳匹配演算法來確定函式模板的引數型別到底是什麼,這就體現了編譯期的多型性。 (2)執行時多型性      C++執行時多型性主要是通過虛擬函式來實現的。體現在具有繼承關係的父類和子類之間,子類重新定義父類的成員函式成為覆蓋或者重寫,而虛擬函式允許子類重新定義父類的成員函式,即重寫父類的成員函式。      下面舉例說明一下:
#include <iostream>
using namespace std;

class A{
public:
     void f1()
     {
          cout<<"A::f1()"<<endl;
     }
     virtual void f2()
     {
          cout<<"A::f2()"<<endl;
     }
};

class B:public A
{
public:
     //覆蓋
     void f1()
     {
          cout<<"B::f1()"<<endl;
     }
     //重寫
     virtual void f2()
     {
          cout<<"B::f2()"<<endl;
     }
};

int main()
{
     A* p = new B();
     B* q = new B();
     p->f1();          //呼叫A::f1()
     p->f2();          //呼叫B::f2(),體現多型性
q->f1(); //呼叫B::f1() q->f2(); //呼叫B::f2() return 0; }
 說說例2中關於體現多型性的問題,我們在父類即A類中定義了一個虛擬函式f2()——由關鍵字virtual修飾。既然是虛擬函式,允許子類重寫這個函式,於是我們在子類即B類中重寫了函式f2()。之後我們在main函式中定義了一個A類指標p,請注意,雖然定義的是一個父類指標,但是它指向的卻是一個子類的物件(new B()),然後我們用這個父類的指標呼叫f2(),從結果來看,實際上呼叫的是子類的f2(),並不是父類的f2(),這就體現了多型性。雖然p是父類指標,但是它指向的是子類物件,而且呼叫的又是虛擬函式,那麼在執行期,就會找到動態繫結到父類指標上的子類物件,然後查詢子類的虛擬函式表,找到函式f2()的入口地址,從而呼叫子類的f2()函式,這就是執行期多型。
     接下來我們再來看看p->f1();這句話,從執行結果來看,呼叫的是父類的f1()函式,這裡是為什麼沒有體現多型呢?原因很簡單,因為f1()不是虛擬函式,所以根本就沒有多型性,雖然子類和父類都有f1()函式,但是子類僅僅是覆蓋或者說是隱藏了父類的f1()函式,注意這裡不是重寫,是覆蓋。而p是父類指標,所以只能呼叫父類的f1()函式。而指標q的型別為子類指標,所以q->f1();呼叫子類的函式f1(),q->f2();呼叫子類的函式f2(); (3)C++純虛擬函式  定義:純虛擬函式是在基類中宣告的虛擬函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法,基類中實現純虛擬函式的方法是在函式原型後面加“=0”。例如:
virtual void f() = 0;

為什麼要引入純虛擬函式: 1、為了使用多型特性,我們必須在基類中定義虛擬函式。  2、在很多情況下,基類本身生成物件是不合情理的。例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成物件明顯不合常理。 為了解決上述問題,引入了純虛擬函式的概念,將函式定義為純虛擬函式(方法:virtual ReturnType Function()= 0;),則編譯器要求在派生類中必須予以重寫以實現多型性。同時含有純虛擬函式的類稱為抽象類,它不能生成物件。純虛擬函式永遠不會被呼叫,它們主要用來統一管理子類物件。