小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C++中虛函數(shù)與純虛函數(shù)的用法

 herowuking 2015-06-27

本文較為深入的分析了C++中虛函數(shù)與純虛函數(shù)的用法,對(duì)于學(xué)習(xí)和掌握面向?qū)ο蟪绦蛟O(shè)計(jì)來(lái)說(shuō)是至關(guān)重要的。具體內(nèi)容如下:

首先,面向?qū)ο蟪绦蛟O(shè)計(jì)(object-oriented programming)的核心思想是數(shù)據(jù)抽象、繼承、動(dòng)態(tài)綁定。通過(guò)數(shù)據(jù)抽象,可以使類的接口與實(shí)現(xiàn)分離使用繼承,可以更容易地定義與其他類相似但不完全相同的新類,使用動(dòng)態(tài)綁定,可以在一定程度上忽略相似類的區(qū)別,而以統(tǒng)一的方式使用它們的對(duì)象。

虛函數(shù)的作用是實(shí)現(xiàn)多態(tài)性(Polymorphism),多態(tài)性是將接口與實(shí)現(xiàn)進(jìn)行分離,采用共同的方法,但因個(gè)體差異而采用不同的策略。純虛函數(shù)則是一種特殊的虛函數(shù)。虛函數(shù)聯(lián)系到多態(tài),多態(tài)聯(lián)系到繼承。所以本文中都是在繼承層次上做文章。沒(méi)了繼承,什么都沒(méi)得談。

一、虛函數(shù)

1 . 定義

在C++中,基類必須將它的兩種成員函數(shù)區(qū)分開(kāi)來(lái):一種是基類希望其派生類進(jìn)行覆蓋的函數(shù);另一種是基類希望派生類直接繼承而不要改變的函數(shù)。對(duì)于前者,基類通過(guò)在函數(shù)之前加上virtual關(guān)鍵字將其定義為虛函數(shù)(virtual)。

1
2
3
4
5
6
7
8
9
class Base{ // 基類
public:
  virtual int func(int n) const;
};
  
class Derive_Class : public Base{
public:
  int func(int n) const; // 默認(rèn)也為虛函數(shù)
};

當(dāng)我們?cè)谂缮愔懈采w某個(gè)函數(shù)時(shí),可以在函數(shù)前加virtual關(guān)鍵字。然而這不是必須的,因?yàn)橐坏┠硞€(gè)函數(shù)被聲明成虛函數(shù),則所有派生類中它都是虛函數(shù)。任何構(gòu)造函數(shù)之外的非靜態(tài)函數(shù)都可以是虛函數(shù)。派生類經(jīng)常(但不總是)覆蓋它繼承的虛函數(shù),如果派生類沒(méi)有覆蓋其基類中某個(gè)虛函數(shù),則該虛函數(shù)的行為類似于其他的普通成員,派生類會(huì)直接繼承其在基類中的版本。

2 . 動(dòng)態(tài)綁定

當(dāng)我們使用基類的引用(或指針)調(diào)用一個(gè)虛函數(shù)時(shí)將發(fā)生動(dòng)態(tài)綁定(dynamic binding)。因?yàn)槲覀冎钡竭\(yùn)行時(shí)才能知道到底調(diào)用了哪個(gè)版本的虛函數(shù),可能是基類中的版本也可能是派生類中的版本,判斷的依據(jù)是引用(或指針)所綁定的對(duì)象的真實(shí)類型。與非虛函數(shù)在編譯時(shí)綁定不同,虛函數(shù)是在運(yùn)行時(shí)選擇函數(shù)的版本,所以動(dòng)態(tài)綁定也叫運(yùn)行時(shí)綁定(run-time binding)。

3 . 靜態(tài)類型與動(dòng)態(tài)類型

靜態(tài)類型指的是變量聲明時(shí)的類型或表達(dá)式生成的類型,它在編譯時(shí)總是已知的;動(dòng)態(tài)類型指的是變量或表達(dá)式表示的內(nèi)存中的對(duì)象的類型,它直到運(yùn)行時(shí)才可知。當(dāng)且僅當(dāng)通過(guò)基類的指針或引用調(diào)用虛函數(shù)時(shí),才會(huì)在運(yùn)行時(shí)解析該調(diào)用,也只有在這種情況下對(duì)象的動(dòng)態(tài)類型才有可能與靜態(tài)類型不同。如果表達(dá)式既不是引用也不是指針,則它的動(dòng)態(tài)類型永遠(yuǎn)與靜態(tài)類型一致。

4 . final和override

派生類中如果定義了一個(gè)函數(shù)與基類中虛函數(shù)同名但形參列表不同,編譯器會(huì)認(rèn)為這是派生類新定義的函數(shù)。如果我們的意圖本是覆蓋虛函數(shù),則這種錯(cuò)誤很難發(fā)現(xiàn)。通過(guò)在派生類中的虛函數(shù)最后加override關(guān)鍵字使得意圖更加清晰。如果我們使用override標(biāo)記了某個(gè)函數(shù),但該函數(shù)并沒(méi)有覆蓋已存在的虛函數(shù),編譯器將報(bào)錯(cuò)。

1
2
3
4
5
6
7
8
9
class Base{ // 基類
public:
  virtual int func(int a, int b) const;
};
  
class Derive_Class : public Base{
public:
  int func(int a) const override; // 報(bào)錯(cuò),沒(méi)有覆蓋虛函數(shù)
};

如果我們定義一個(gè)類,并不希望它被繼承。或者希望某個(gè)函數(shù)不被覆蓋,則可以把類或者函數(shù)指定為final,則之后任何嘗試?yán)^承該類或覆蓋該函數(shù)的操作將引發(fā)錯(cuò)誤。

1
2
3
4
class Base final { /*  */ };   // 基類不能被繼承
class Derive_Class : public Base { /* */ };   // 報(bào)錯(cuò)
  
void func(int) const final;  // 不允許后續(xù)的其他類覆蓋func(int)

5 . 回避虛函數(shù)的機(jī)制

在某些情況下,我們希望對(duì)虛函數(shù)的調(diào)用不要進(jìn)行動(dòng)態(tài)綁定,而是強(qiáng)迫其執(zhí)行虛函數(shù)的某個(gè)特定版本。可以使用作用域運(yùn)算符實(shí)現(xiàn)這一目的。

1
2
// 強(qiáng)行調(diào)用基類中定義的函數(shù)版本而不管baseP的動(dòng)態(tài)類型是什么
int a = baseP->Base::func(42);

如果一個(gè)派生類虛函數(shù)需要調(diào)用它的基類版本,但是沒(méi)有使用作用域運(yùn)算符,則在運(yùn)行時(shí)該調(diào)用將被解析為對(duì)派生類版本自身的調(diào)用,從而導(dǎo)致無(wú)限遞歸。

二、純虛函數(shù)

1 . 定義

為了方便使用多態(tài)特性,我們常常需要在基類中定義虛函數(shù)。在許多情況下,在基類中不能對(duì)虛函數(shù)給出有意義的實(shí)現(xiàn)。為了讓虛函數(shù)在基類什么也不做,引進(jìn)了“純虛函數(shù)”的概念,使函數(shù)無(wú)須定義。我們通過(guò)在函數(shù)體的位置(即在聲明語(yǔ)句的分號(hào)之前)書(shū)寫(xiě)=0就可以將一個(gè)虛函數(shù)說(shuō)明為純虛函數(shù)(pure virtual)。其中,=0只能出現(xiàn)在類內(nèi)部的虛函數(shù)聲明語(yǔ)句處:

1
2
3
4
class Base{ // 抽象基類
public:
  virtual int func(int n) const =0;
};

需要注意的是,我們也可以為純虛函數(shù)提供定義,不過(guò)函數(shù)體必須定義在類的外部。

2 . 抽象基類

含有(或者未經(jīng)覆蓋直接繼承)純虛函數(shù)的類叫抽象基類(abstract base class)。抽象基類負(fù)責(zé)定義接口,而后續(xù)的其他類可以覆蓋該接口。如果派生類中沒(méi)有重新定義純虛函數(shù),而只是繼承基類的純虛函數(shù),則這個(gè)派生類仍然還是一個(gè)抽象基類。因?yàn)槌橄蠡惡屑兲摵瘮?shù)(沒(méi)有定義),所以我們不能創(chuàng)建一個(gè)抽象基類的對(duì)象,但可以聲明指向抽象基類的指針或引用。

1
Base base;  // 錯(cuò)誤,不能實(shí)例化抽象基類

總結(jié):

①.虛函數(shù)必須實(shí)現(xiàn),不實(shí)現(xiàn)編譯器會(huì)報(bào)錯(cuò)。

②.父類和子類都有各自的虛函數(shù)版本。由多態(tài)方式在運(yùn)行時(shí)動(dòng)態(tài)綁定。

③.通過(guò)作用域運(yùn)算符可以強(qiáng)行調(diào)用指定的虛函數(shù)版本。

④.純虛函數(shù)聲明如下:virtual void funtion()=0; 純虛函數(shù)無(wú)需定義。包含純虛函數(shù)的類是抽象基類,抽象基類不能創(chuàng)建對(duì)象,但可以聲明指向抽象基類的指針或引用。

⑤.派生類實(shí)現(xiàn)了純虛函數(shù)以后,該純虛函數(shù)在派生類中就變成了虛函數(shù),其子類可以再對(duì)該函數(shù)進(jìn)行覆蓋。

⑥.析構(gòu)函數(shù)通常應(yīng)該是虛函數(shù),這樣就能確保在析構(gòu)時(shí)調(diào)用正確的析構(gòu)函數(shù)版本。

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶 評(píng)論公約

      類似文章 更多