官术网_书友最值得收藏!

2.4 多態(tài)和虛函數(shù)

多態(tài)性是面向對象程序設計的重要特性之一,它與封裝性和繼承性構成了面向對象程序設計的三大特性。所謂多態(tài)性,是指不同類型的對象接收相同的消息時產生不同的行為。這里的消息主要是指對類的成員函數(shù)的調用,而不同的行為是指成員函數(shù)的不同實現(xiàn)。例如,函數(shù)重載就是多態(tài)性的典型例子之一。

2.4.1 多態(tài)概述

在C++中,多態(tài)性可分為兩種:編譯時的多態(tài)性和運行時的多態(tài)性。編譯時的多態(tài)性是通過函數(shù)或運算符的重載來實現(xiàn)的。而運行時的多態(tài)性是通過虛函數(shù)來實現(xiàn)的,它指在程序執(zhí)行之前,根據(jù)函數(shù)和參數(shù)還無法確定應該調用哪一個函數(shù),必須在程序的執(zhí)行過程中,根據(jù)具體的執(zhí)行情況動態(tài)地確定。

與這兩種多態(tài)性方式相對應的是兩種編譯方式:靜態(tài)聯(lián)編和動態(tài)聯(lián)編。所謂聯(lián)編(binding,又稱綁定),就是將一個標識符和一個存儲地址聯(lián)系在一起的過程,或是一個源程序經過編譯、連接,最后生成可執(zhí)行代碼的過程。

靜態(tài)聯(lián)編指這種聯(lián)編是在編譯階段完成的,由于聯(lián)編過程是在程序運行前完成的,所以稱為早期聯(lián)編。動態(tài)聯(lián)編是指這種聯(lián)編要在程序運行時動態(tài)進行,所以又稱晚期聯(lián)編。

一般來說,在靜態(tài)聯(lián)編的方式下,同一個成員函數(shù)在基類和派生類中的不同版本是不會在運行時根據(jù)程序代碼的指定進行自動綁定的。因此,必須通過類的虛函數(shù)機制,才能實現(xiàn)基類和派生類中的成員函數(shù)不同版本的動態(tài)聯(lián)編。

2.4.2 虛函數(shù)

先來看一個虛函數(shù)應用實例。

【例Ex_VirtualFunc】 虛函數(shù)的使用

#include <iostream.h>
class CShape
{
public:
    virtual float area()               // 將area定義成虛函數(shù)
    {   return 0.0; }
};
class CTriangle : public CShape
{
public:
    CTriangle(float h, float w)
    {   H=h;    W=w;   }
    float area()
    {   return(float)(H*W*0.5); }
private:
    float H, W;
};
class CCircle : public CShape
{
public:
    CCircle(float r)
    {   R=r;
    }
    float area()
    {   return(float)(3.14159265*R*R);
    }
private:
    float R;
};
int  main()
{
    CShape *s[2];
    s[0] = new CTriangle(3,4);
    cout<<s[0]->area()<<endl;
    s[1] = new CCircle(5);
    cout<<s[1]->area()<<endl;
    return 0;
}

程序運行結果如下:

6

78.5398

代碼中,虛函數(shù)area是通過在基類的area函數(shù)的前面加上virtual關鍵字來實現(xiàn)的。程序中*s[2]是定義的基類CShape指針,語句“s[0]=new CTriangle(3,4);”是將s[0]指向派生類CTriangle,因而“s[0]->area();”實際上是調用CTriangle類的area成員函數(shù),結果是6;同樣可以分析s[1]->area()的結果。

從這個例子可以看出,正是通過虛函數(shù),達到了用基類指針訪問派生類對象成員函數(shù)的目的,從而使一個函數(shù)具有多種不同的版本,這一點與重載函數(shù)相似,只不過虛函數(shù)的不同版本是在該基類的派生類中重新進行定義的。這樣,只要聲明了基類指針就可以使不同的派生類對象產生不同的函數(shù)調用,實現(xiàn)了程序的運行時多態(tài)。

需要說明的是:

(1)虛函數(shù)在重新定義時,參數(shù)的個數(shù)和類型必須和基類中的虛函數(shù)完全匹配,這一點和函數(shù)重載完全不同。

(2)只有通過基類指針才能實現(xiàn)虛函數(shù)的多態(tài)性,若虛函數(shù)的調用是通過普通方式來進行的,則不能實現(xiàn)其多態(tài)性。例如:

CShape  ss;
cout<<ss.area()<<endl;

輸出的結果為0.0。

(3)如果不使用new來創(chuàng)建相應的派生類對象指針,也可通過使用&運算符來獲取對象的地址。例如:

void main()
{
    CShape *p1, *p2;
    CTriangle tri(3, 4);
    CCircle cir(5);
    p1=&tri; p2=&cir;
    cout<<p1->area()<<endl;
    cout<<p2->area()<<endl;
}

(4)虛函數(shù)必須是類的一個成員函數(shù),不能是友元函數(shù),也不能是靜態(tài)的成員函數(shù)。

(5)可把析構函數(shù)定義為虛函數(shù),但不能將構造函數(shù)定義為虛函數(shù)。通常在釋放基類中及其派生類中動態(tài)申請存儲空間時,也要把析構函數(shù)定義為虛函數(shù),以便實現(xiàn)撤銷對象時的多態(tài)性。

2.4.3 純虛函數(shù)和抽象類

在定義一個基類時,有時會遇到這樣的情況:無法定義基類中虛函數(shù)的具體實現(xiàn),其實現(xiàn)完全依賴于其不同的派生類。例如,一個“形狀類”(基類)由于沒有確定的具體形狀,因此其計算面積的函數(shù)也就無法實現(xiàn)。這時可將基類中的虛函數(shù)聲明為純虛函數(shù)

聲明純虛函數(shù)的一般格式為:

virtual <函數(shù)類型><函數(shù)名>(<形參表>) = 0;

顯然,它與一般虛函數(shù)不同的是:在純虛函數(shù)的形參表后面多了個“= 0”。把函數(shù)名賦為0,本質上是將指向函數(shù)的指針的初值賦為0。需要說明的是,純虛函數(shù)不能有具體的實現(xiàn)代碼。

抽象類是指至少包含一個純虛函數(shù)的特殊的類。它本身不能被實例化,也就是說不能聲明一個抽象類的對象。必須通過繼承得到派生類后,在派生類中定義了純虛函數(shù)的具體實現(xiàn)代碼,才能獲得一個派生類的對象。

下面舉例說明純虛函數(shù)和抽象類的應用。

【例Ex_PureVirtualFunc】 純虛函數(shù)和抽象類的使用

#include <iostream.h>
class CShape
{
public:
    virtual float area()=0;               // 將area定義成純虛函數(shù)
};
class CTriangle:public CShape
{
public:
    CTriangle(float h, float w)
    {   H=h;    W=w;
    }
    float area()                         // 在派生類中定義純虛函數(shù)的具體實現(xiàn)代碼
    {   return(float)(H*W*0.5);
    }
private:
    float H, W;
};
class CCircle:public CShape
{
public:
    CCircle(float r)
    {   R=r;
    }
    float area()                         // 在派生類中定義純虛函數(shù)的具體實現(xiàn)代碼
    {   return(float)(3.14159265*R*R);
    }
private:
    float R;
};
int  main()
{
    CShape *pShape;
    CTriangle tri(3, 4);
    cout<<tri.area()<<endl;
    pShape = &tri;
    cout<<pShape->area()<<endl;
    CCircle cir(5);
    cout<<cir.area()<<endl;
    pShape = &cir;
    cout<<pShape->area()<<endl;
    return 0;
}

程序運行結果如下:

6

6

78.5398

78.5398

從這個示例可以看出,與虛函數(shù)使用方法相同,也可以聲明指向抽象類的指針,雖然該指針不能指向任何抽象類的對象(因為不存在),但可以通過該指針獲得對派生類成員函數(shù)的調用。事實上,純虛函數(shù)是一個特殊的虛函數(shù)。

主站蜘蛛池模板: 威信县| 双鸭山市| 江陵县| 南皮县| 财经| 南岸区| 汉寿县| 启东市| 阿荣旗| 灵石县| 旬邑县| 祁连县| 龙门县| 永泰县| 唐海县| 象州县| 望奎县| 礼泉县| 正镶白旗| 沅江市| 沙雅县| 颍上县| 特克斯县| 金塔县| 天气| 文安县| 宜春市| 绥德县| 屯昌县| 阿拉善左旗| 石台县| 天全县| 宜君县| 南江县| 阿勒泰市| 嘉义市| 长白| 龙江县| 秦安县| 丹凤县| 中阳县|