日韩在线免费播放-日韩在线免费av-日韩在线免费-日韩在线毛片-国产高清不卡视频-国产高清不卡

當前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > C++覆蓋和遮蔽

C++覆蓋和遮蔽 時間:2019-03-13      來源:華清遠見

多態(tài)函數(shù)是指在運行期才將函數(shù)入口地址與函數(shù)名綁定的函數(shù),僅有虛函數(shù)才是多態(tài)。但是除了虛函數(shù)以外,重載和遮蔽同樣具有函數(shù)名相同的特征,在此做一下區(qū)分。為了說明方便,我們引入函數(shù)簽名這一概念。函數(shù)簽名包括函數(shù)名和函數(shù)參數(shù)的個數(shù)、順序以及參數(shù)數(shù)據(jù)類型。

例1:

void f()

void g()

void f(int)

例2:

void f(int)

void f(double)

例3:

void f(double, int)

void f(int, double)

為了理解函數(shù)簽名的含義,我們先來看一下上面的三個例子。例1中函數(shù)f()和函數(shù)g()函數(shù)名不同,因此這兩個函數(shù)的函數(shù)簽名不同,f()函數(shù)和f(int)函數(shù)一個有參數(shù),一個沒有參數(shù),函數(shù)簽名同樣不同,g()函數(shù)和f(int)函數(shù)函數(shù)名不同并且函數(shù)參數(shù)個數(shù)也不同,因此這兩個函數(shù)的函數(shù)簽名也是不相同的。例2中兩個函數(shù)函數(shù)名相同,函數(shù)參數(shù)個數(shù)相同,但是函數(shù)參數(shù)的類型不同,因此這兩個函數(shù)的函數(shù)簽名也不是相同的。例3中的兩個函數(shù),函數(shù)名相同,函數(shù)參數(shù)個數(shù)相同,函數(shù)參數(shù)類型也是相同的,都是一個double類型和一個int類型的,只不過函數(shù)參數(shù)的順序是不相同,如此一來這兩個函數(shù)的函數(shù)簽名同樣是不相同的。

需要注意的是函數(shù)簽名并不包含函數(shù)返回值部分,如果兩個函數(shù)僅僅只有函數(shù)返回值不同,那么系統(tǒng)是無法區(qū)分這兩個函數(shù)的,此時編譯器會提示語法錯誤。

例4:

int f(int, double)

void f(int, double)

在本例中,兩個函數(shù)的函數(shù)名相同,函數(shù)參數(shù)個數(shù)相同,函數(shù)參數(shù)類型相同,函數(shù)參數(shù)順序相同,如此一來兩個函數(shù)的函數(shù)簽名是相同的。但是這兩個函數(shù)的返回值不同,僅憑函數(shù)返回值,編譯器無法區(qū)分這兩個函數(shù),編譯器提示語法錯誤。

了解了函數(shù)簽名的含義之后我們再來看一下重載、覆蓋和遮蔽。

1) 重載

函數(shù)重載是指兩個函數(shù)具有相同的函數(shù)名,但是函數(shù)參數(shù)個數(shù)或參數(shù)類型不同。函數(shù)重載多發(fā)生在頂層函數(shù)之間或者同一個類中,函數(shù)重載不需要構(gòu)成繼承關(guān)系。(函數(shù)返回值不同不能構(gòu)成函數(shù)重載)

例5:

class base

{

public :

base();

base(inta);

base(inta, int b);

base(base &);

int fun(int a);

int fun(double a);

int fun(int a, int b);

private:

int x;

int y;

};

int g(int a);

int g(double a);

int g(int a, int b);

在本例中,我們列出了幾種函數(shù)重載的情形。首先是函數(shù)的構(gòu)造函數(shù)重載,我們在類中聲明了四個構(gòu)造函數(shù),這四個函數(shù)構(gòu)成重載的關(guān)系,前面三個函數(shù)之間只是函數(shù)參數(shù)數(shù)目不同,第四個構(gòu)造函數(shù)為拷貝構(gòu)造函數(shù),該函數(shù)與前面的默認構(gòu)造函數(shù)和兩個帶參構(gòu)造函數(shù)參數(shù)類型不同。類中的成員函數(shù)同樣可以進行重載,如本例中base類的三個fun函數(shù)。這兩種情況是類內(nèi)部的函數(shù)重載,在類外部頂層函數(shù)也同樣能夠成函數(shù)重載關(guān)系,如本例中的g函數(shù),這三個函數(shù)都是頂層函數(shù),由于函數(shù)名相同,但是函數(shù)參數(shù)不同,構(gòu)成函數(shù)重載關(guān)系。

函數(shù)重載是編譯期綁定,它并不是多態(tài)。 (類似于多態(tài)的表現(xiàn)形式,又有所不同)

2) 覆蓋(重寫override)

覆蓋構(gòu)成條件和多態(tài)構(gòu)成條件是相同的,覆蓋是一種函數(shù)間的表現(xiàn)關(guān)系,而多態(tài)描述的是函數(shù)的一種性質(zhì),二者所描述的其實是同一種語法現(xiàn)象。

覆蓋首先要求有繼承關(guān)系,其次是要求構(gòu)成繼承關(guān)系的兩個類中必須具有相同函數(shù)名的成員函數(shù),并且這兩個成員函數(shù)必須是虛成員函數(shù),具備這兩個條件后,派生類中的虛成員函數(shù)則會覆蓋基類中的同名的虛成員函數(shù)。如果我們通過基類指針或引用來調(diào)用虛成員函數(shù),則會形成多態(tài)。

例6:

#include <iostream>

using namespace std;

class base

{

public :

virtual void vir1(){}

virtual void vir2(){}

//virtual ~base();

};

class derived : public base

{

public:

void vir1(){}

void vir2(){}

};

int main()

{

base *p = new derived;

p->vir1();

p->vir2();

delete p;

return 0;

}

本例是一個非常簡單的多態(tài)的示例程序,base類和derived類構(gòu)成繼承關(guān)系,在這兩個類中成員函數(shù)vir1和vir2同名,并且這兩個同名函數(shù)都被聲明為了虛函數(shù)。如此一來則構(gòu)成了函數(shù)覆蓋,派生類中的vir1函數(shù)覆蓋了基類中的vir1函數(shù),派生類中的vir2函數(shù)覆蓋了基類中的vir2函數(shù)。在主函數(shù)中通過基類指針調(diào)用vir1和vir2虛函數(shù),構(gòu)成多態(tài),這兩個函數(shù)的運行為運行期綁定。

函數(shù)覆蓋屬于運行期綁定,但是要注意如果函數(shù)不是虛函數(shù),則無論采用什么方法調(diào)用函數(shù)均為編譯期綁定。如果我們將例6中的基類中的兩個virtual關(guān)鍵字去掉,則主函數(shù)中調(diào)用vir1和vir2函數(shù)屬于編譯期綁定,無論p指向的是派生類對象或者是基類對象,執(zhí)行的都將會是基類的vir1和vir2函數(shù)。

3) 遮蔽

函數(shù)遮蔽同樣要求構(gòu)成繼承關(guān)系,構(gòu)成繼承關(guān)系的兩個類中具有相同函數(shù)名的函數(shù),如果這兩個函數(shù)不夠成覆蓋關(guān)系,則就構(gòu)成了遮蔽關(guān)系。遮蔽理解起來很簡單,只要派生類與基類中具有相同函數(shù)名(注意不是相同函數(shù)名,只需要相同函數(shù)名就可以了)并且不構(gòu)成覆蓋關(guān)系即為遮蔽。

遮蔽可以分為兩種情況,一種是非虛函數(shù)之間,另一種則是虛函數(shù)之間。我們通過程序示例來分別介紹這兩種遮蔽情況。

例7:

#include<iostream>

using namespace std;

class base

{

public:

void vir1(){cout << "base vir1" << endl;}

void vir2(){cout << "base vir2" << endl;}

};

class derived : public base

{

public:

void vir1(){cout << "derived vir1" << endl;}

void vir2(int){cout << "derived vir2" << endl;}

};

int main()

{

base* p = new derived;  // 自由存儲區(qū)分配

p->vir1();

p->vir2();

delete p;

derived d;              // 棧分配

d.vir1();

d.vir2(5);

d.base::vir1();

d.base::vir2();

return  0;

}

在本例中沒有虛函數(shù),base類和derived類構(gòu)成繼承關(guān)系,因為構(gòu)成繼承關(guān)系的兩個類中有同名函數(shù),因此構(gòu)成了函數(shù)遮蔽。派生類中的vir1函數(shù)遮蔽了基類中的vir1函數(shù),派生類中的vir2函數(shù)遮蔽了基類中的vir1函數(shù)。需要注意的是雖然派生類中的vir2函數(shù)和基類中的vir2函數(shù)的函數(shù)簽名不同,但是只需要函數(shù)名相同就構(gòu)成函數(shù)遮蔽。我們接著來分析一下主函數(shù),主函數(shù)中我們先是定義了基類類型的指針,指針指向的是派生類對象,然后通過指針調(diào)用函數(shù)vir1和vir2,這個時候因為并不構(gòu)成多態(tài),因此調(diào)用的還是基類的vir1和vir2函數(shù)。之后定義了一個派生類對象d,通過該對象調(diào)用vir1和vir2函數(shù),因為派生類中的vir1和vir2遮蔽了基類中的vir1和vir2函數(shù),因此直接調(diào)用的將會是派生類中的vir1和vir2函數(shù)。如果需要通過派生類對象調(diào)用被遮蔽的基類中的函數(shù),則需要通過域解析操作符來處理,在本例的最后d.base::vir1();和d.base::vir2()就是這么做的。這個程序的最終運行結(jié)果如下:

base vir1

base vir2

derived vir1

derived vir2

base vir1

base vir2

如果構(gòu)成繼承關(guān)系的兩個類中包含同名的虛函數(shù),則情況非常復(fù)雜,當然要判斷還是非常簡單,還是那個原則:如果沒有構(gòu)成覆蓋則為遮蔽。覆蓋要求的是函數(shù)簽名相同,而遮蔽只需要函數(shù)名相同。

例8:

#include<iostream>

using namespace std;

class base

{

public :

virtual void vir1(){cout << "base vir1" <<endl;}

virtual void vir2(){cout << "base vir2" <<endl;}

};

class derived : public base

{

public:

virtual void vir1(){cout << "derived vir1" << endl;}

virtual void vir2(int){cout << "derived vir2" << endl;}

};

int main()

{

base *p;

p = new derived;

p->vir1();    // 多態(tài)

p->vir2();    // 常規(guī)調(diào)用

delete p;

derived d;

d.vir1();      // 常規(guī)調(diào)用 

d.vir2(5);     // 常規(guī)調(diào)用 

d.base::vir1();

d.base::vir2();

return  0;

}

在這個程序中,定義了兩個類,base類和derived類,這兩個類構(gòu)成繼承關(guān)系,派生類和基類中包含同名的函數(shù),并且同名的函數(shù)均為虛函數(shù)。針對這兩個同名函數(shù),我們一個一個來分析一下,首先來看一下vir1,基類和派生類中的vir1函數(shù)的函數(shù)簽名是相同的,而且又是虛函數(shù),構(gòu)成了函數(shù)覆蓋關(guān)系。再來看一下vir2函數(shù),基類中的vir2函數(shù)和派生類中的vir2函數(shù)函數(shù)名相同,但函數(shù)參數(shù)不同,則它們的函數(shù)簽名不同,因此派生類中的vir2函數(shù)和基類中的vir1函數(shù)不構(gòu)成函數(shù)覆蓋,既然函數(shù)名相同,那么可以構(gòu)成函數(shù)遮蔽。

接著我們同樣來看一下主函數(shù),在主函數(shù)中,我們定義了一個基類類型的指針,指針指向派生類對象,之后通過該指針分別調(diào)用vir1和vir2函數(shù)。由于vir1是構(gòu)成函數(shù)覆蓋,因此通過基類指針調(diào)用vir1構(gòu)成多態(tài),由于p指針指向的是派生類對象,故調(diào)用的vir1函數(shù)是派生類中的vir1函數(shù)。派生類中的vir2函數(shù)和基類中的vir2函數(shù)只構(gòu)成函數(shù)遮蔽,因此通過基類類型指針調(diào)用vir2函數(shù)并不會形成多態(tài),最終調(diào)用的是基類中的vir2函數(shù)。之后定義了派生類對象d,通過派生類對象d調(diào)用的函數(shù)只能是派生類中的函數(shù),當然也包括從基類中繼承來的函數(shù)。d.vir1()和d.vir2(5)這兩個函數(shù)調(diào)用語句調(diào)用的都是派生類中新增的成員函數(shù),派生類中的vir1函數(shù)雖然和基類中的vir1函數(shù)構(gòu)成覆蓋關(guān)系,但是由于沒有通過基類指針或引用來調(diào)用,因此也沒有構(gòu)成多態(tài),如此一來,如果需要通過對象來調(diào)用從基類中繼承過來的vir1函數(shù),同樣是需要域解析操作符。派生類中的vir2函數(shù)和基類中vir2函數(shù)構(gòu)成遮蔽,因此通過對象和成員選擇符調(diào)用的仍是派生類中新增的vir2函數(shù),如果想調(diào)用基類中的vir2函數(shù),則需要通過域解析操作符。例8程序運行結(jié)果如下:

derived vir1

base vir2

derived vir1

derived vir2

base vir1

base vir2

以上總結(jié)了函數(shù)名相同的所有情況,函數(shù)名相同利用的好可以為程序設(shè)計帶來較大的便利,使用的不好則容易誤導(dǎo)程序設(shè)計人員。一般來講,函數(shù)名相同通常會用在以下幾種情況中:

頂層函數(shù)的函數(shù)重載。對于程序設(shè)計人員而言,實現(xiàn)功能相同但所處理數(shù)據(jù)類型不同的函數(shù)時,采用函數(shù)重載的方式將會帶來極大的方便。例如設(shè)計一個求絕對值函數(shù),針對整型和double類型各設(shè)及一個abs函數(shù),調(diào)用時而無需關(guān)注參數(shù)類型,這樣的設(shè)計是很方便的。

類中的成員函數(shù)的重載,這種函數(shù)重載和頂層函數(shù)重載同樣能給我們的程序帶來方便。

類中的構(gòu)造函數(shù)重載,設(shè)計多個構(gòu)造函數(shù),用于不同的初始化對象方式。

在繼承層次中為了使用多態(tài)特性而采用相同函數(shù)簽名。

除此之外函數(shù)名相同還會導(dǎo)致繼承層次中的函數(shù)遮蔽,而函數(shù)遮蔽這一特性通常會使得程序難以理解,因此建議謹慎使用函數(shù)遮蔽機制。

上一篇:Java開發(fā):線程創(chuàng)建的三種方式

下一篇:linux開發(fā):linux最大線程數(shù)分析

熱點文章推薦
華清學(xué)員就業(yè)榜單
高薪學(xué)員經(jīng)驗分享
熱點新聞推薦
前臺專線:010-82525158 企業(yè)培訓(xùn)洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權(quán)所有 ,京ICP備16055225號-5京公海網(wǎng)安備11010802025203號

回到頂部

主站蜘蛛池模板: 谍影 电视剧| 免费头像图片| 黑红| sm在线| 矢部享佑| 色在线观看| 诺曼瑞杜斯| 辐射避难所掉脑袋问题答案 | 飞天电影| 缺宅男女电视剧| 最危险的游戏| 杰西卡·布朗·芬德利| 母亲电影韩国完整版免费观看| 日本大片ppt免费ppt电影| 韩国三级播放| 高等学校毕业生登记表自我鉴定怎么写| 电影在线观看高清完整版免费| 江苏卫视今天节目表| 创业史全文免费阅读| 李欣聪个人资料| 进击的巨人2| 《遇见你之后》电影在线观看| 梦想建筑师泰国百合剧| 《西游降魔篇》2| 少年团时代成员| 喝醉的图片| 母亲とが话しています免费| 田教授的28个保姆演员表| 男女拍拍拍拍拍拍| 冷血惊魂| 一起再看流星雨| 仁爱版九年级英语上册教案| 光彩年华| 恰纳卡莱之战完整版在线观看| 欧布奥特曼普通话版| 世界上最有杀气的国歌| 小孩几个月会翻身| 拉字至上q世代| 老师好 演员表| 伊人1314| 荒野求生无马赛原版在哪里看|