明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

C++重寫重載_詳細(xì)說(shuō)明C++中的函數(shù)名字重寫、重載、重定義程序應(yīng)用案例

[摘要]C++重寫重載_詳解C++中的函數(shù)名字重寫、重載、重定義程序應(yīng)用實(shí)例重載、重寫是必須要知道,因?yàn)橛猛咎珡V泛;至于隱藏嗎,完全是C++為面試官設(shè)計(jì)的(^_^等待挨磚)。有些面試主考官總喜歡拿這三個(gè)概念...

C++重寫重載_詳解C++中的函數(shù)名字重寫、重載、重定義程序應(yīng)用實(shí)例

重載、重寫是必須要知道,因?yàn)橛猛咎珡V泛;至于隱藏嗎,完全是C++為面試官設(shè)計(jì)的(^_^等待挨磚)。有些面試主考官總喜歡拿這三個(gè)概念去為難你,考察你的C++基礎(chǔ)是否牢固。所以為了面試、這三個(gè)概念還是需要我們?nèi)^(qū)分一下。

JAVA中語(yǔ)言中方法(函數(shù))調(diào)用有兩種特殊的形態(tài):重載與重寫;而C++由于增加了virtual這個(gè)虛函數(shù)關(guān)鍵字,給函數(shù)調(diào)用又增加了變數(shù):除了重載、重寫(也稱覆蓋)之外還多了隱藏這么一說(shuō)。

C++中經(jīng)常出現(xiàn)函數(shù)名字一樣,但參數(shù)列表或返回值不同的函數(shù),要搞清楚函數(shù)的正確調(diào)用關(guān)系,需理清三個(gè)概念:重寫(override)、重載(overload)、重定義(redefine)。

1、重載的特征:在同一個(gè)類中;函數(shù)名字相同;參數(shù)不同;virtual 關(guān)鍵字可有可無(wú)。

2、重寫(覆蓋)特征是:分別位于派生類與基類;函數(shù)名字相同;參數(shù)相同;基類函數(shù)必須有virtual 關(guān)鍵字(這點(diǎn)非常要注意)。

C++的隱藏規(guī)則使問(wèn)題復(fù)雜性陡然增加。規(guī)則如下:

1、如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無(wú)virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。

2、 如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒(méi)有virtual關(guān)鍵字。此時(shí),基類的函數(shù)被隱藏(注意別與重寫混淆)。

一、三個(gè)基本概念

1、重定義(redefine):派生類對(duì)基類的成員函數(shù)重新定義,即派生類定義了某個(gè)函數(shù),該函數(shù)的名字與基類中的函數(shù)名字一樣。

特點(diǎn):(1)不在同一個(gè)作用域(分別位于基類、派生類) (2)函數(shù)的名字必須相同 (3)對(duì)函數(shù)的返回值、形參列表無(wú)要求

特殊情況:若派生類定義的該函數(shù)與基類的成員函數(shù)完全一樣(返回值、形參列表均相同),且基類的該函數(shù)為virtual,則屬于派生類重寫基類的虛函數(shù)。

作用效果:若重新定義了基類中的一個(gè)重載函數(shù),則在派生類中,基類中該名字的函數(shù)(即其他所有重載版本)都被自動(dòng)隱藏,包括同名的虛函數(shù)。

2、重載(overload):函數(shù)名字相同,但它的形參個(gè)數(shù)或者順序,或者類型不同,但是不能靠返回類型來(lái)判斷。

特點(diǎn):(1)位于同一個(gè)類中 (2)函數(shù)的名字必須相同 (3)形參列表不同(可能是參數(shù)個(gè)數(shù) or 類型 or 順序 不同),返回值無(wú)要求

特殊情況:若某一個(gè)重載版本的函數(shù)前面有virtual修飾,則表示它是虛函數(shù)。但它也是屬于重載的一個(gè)版本

不同的構(gòu)造函數(shù)(無(wú)參構(gòu)造、有參構(gòu)造、拷貝構(gòu)造)是重載的應(yīng)用

作用效果和原理:編譯器根據(jù)函數(shù)不同的參數(shù)表,將函數(shù)體與函數(shù)調(diào)用進(jìn)行早綁定。重載與多態(tài)無(wú)關(guān),只是一種語(yǔ)言特性,與面向?qū)ο鬅o(wú)關(guān)。

3、重寫(override):派生類重定義基類的虛函數(shù),即會(huì)覆蓋基類的虛函數(shù) (多態(tài)性)

特點(diǎn):(1)不在同一個(gè)作用域(分別位于基類、派生類) (2)函數(shù)名、形參列表、返回值相同 (3)基類的函數(shù)是virtual

特殊情況:若派生類重寫的虛函數(shù)屬于一個(gè)重載版本,則該重寫的函數(shù)會(huì)隱藏基類中與虛函數(shù)同名的其他函數(shù)。

作用效果:父類的指針或引用根據(jù)傳遞給它的子類地址或引用,動(dòng)態(tài)地調(diào)用屬于子類的該函數(shù)。這個(gè)晚綁定過(guò)程只對(duì)virtual函數(shù)起作用

具體原理是由虛函數(shù)表(VTABLE)決定的,在第三節(jié)介紹。

[page]
 

二、程序?qū)嵗?/p>

1、兩個(gè)類:基類( 取名Test)和派生類( 取名XX) 名字不規(guī)范,哈哈隨便取得!

基類和派生類的結(jié)構(gòu)

//Base class
class Test
{
public:
int a;

Test()
{
cout<<"Test() 無(wú)參構(gòu)造函數(shù)!"<<>
}

Test(int data)
{
a = data;
cout<<"Test(int data) 有參構(gòu)造函數(shù)!"<<>
}

Test(const Test &tmp)
{
a = tmp.a;
cout<<"Test 拷貝構(gòu)造函數(shù)!!"< }

//基類中對(duì)函數(shù)名f,進(jìn)行了重載。其中最后一個(gè)重載函數(shù)為虛函數(shù)
void f()const
{
cout<<"調(diào)用 void Test::f()"<<>
}

//overload
int f(int data) const
{
cout<<"調(diào)用 Test f(int data)"<<>
return 1;
}

//overload 虛函數(shù)
virtual double f(int dataA,int dataB)
{
cout<<"調(diào)用 Test f(int a,int b)"<<>
return dataA*dataB/2.0;
}

};

class XX: public Test
{
public:
Test atest;//先調(diào)用基類的構(gòu)造函數(shù),然后對(duì)象成員的構(gòu)造函數(shù),最后才是派生類的構(gòu)造函數(shù)

XX()
{
cout<<"XX() 無(wú)參構(gòu)造函數(shù)被調(diào)用!"<<>
}

//對(duì)基類的函數(shù)名f,進(jìn)行了重定義。則會(huì)隱藏基類中的其他f函數(shù)
//redefine
int f() const
{
cout<<" 調(diào)用 XX f()函數(shù)"<<>
return 1;
}

//重寫基類的虛函數(shù)
//redefine override
double f(int dataA,int dataB)
{
cout<<"調(diào)用 XX f(int dataA,int dataB)函數(shù)"<<>
return (dataA+dataB)/2.0;
}
};







分析:基類class Test中定義了名為f的3個(gè)重載函數(shù),其中最后一個(gè)是虛函數(shù)

派生類class XX中對(duì)f進(jìn)行了重定義,所以會(huì)隱藏基類中名為f的版本。其中派生類的double f(int dataA,int dataB)屬于對(duì)虛函數(shù)的重寫

測(cè)試---主程序

int main()
{
//-----test 1------------------------
cout<<"-------test 1------------"<<>
//Base class
Test aaTest;
aaTest.f();
aaTest.f(12);
aaTest.f(10,20);

//derived class
XX d;
d.f();
// d.f(2); //error C2661: 'f' : no overloaded function takes 1 parameters
d.f(10,20);

//--------test 2----------------------------------
cout<<"-------test 2------------"<<>
Test b = d;
b.f();
b.f(10,20);//調(diào)用的是基類的函數(shù),不發(fā)生多態(tài)

//--------test 3----------------------------------------
cout<<"-------test 3------------"<<>
Test &bR = d;//引用
b.f();//f()不是虛函數(shù),調(diào)用基類的函數(shù)
bR.f(10,20);//調(diào)用的是派生類的函數(shù),發(fā)生多態(tài)

//--------test 4--------------------------------------
cout<<"-------test 4------------"<<>
Test* pB = &d;
b.f();
pB->f(10,20);//調(diào)用的是派生類的函數(shù),發(fā)生多態(tài)

return 1;
}



分析:(1)test 1中進(jìn)行了重載測(cè)試,根據(jù)傳遞參數(shù)的不一樣,調(diào)用不同的函數(shù) (早綁定,與多態(tài)無(wú)關(guān))

(2)test 2中Test b = d;定義了一個(gè)基類對(duì)象,用派生類對(duì)象來(lái)進(jìn)行初始化。這會(huì)調(diào)用基類的拷貝構(gòu)造函數(shù),生成基類的對(duì)象b,基類的拷貝構(gòu)造函數(shù)初始化b的VPTR,指向b的VTABLE。因此所有的函數(shù)調(diào)用都只發(fā)生在基類,不會(huì)產(chǎn)生多態(tài)。

這是一個(gè)對(duì)象切片過(guò)程(參見(jiàn)《C++編程思想.第二版》P370),對(duì)象切片是當(dāng)它拷貝到一個(gè)新的對(duì)象時(shí),會(huì)去掉原來(lái)對(duì)象的一部分,而不是像使用指針或引用那樣簡(jiǎn)單地改變地址的內(nèi)容。

(3)test 3和test 4中,定義的基類指針和引用,故會(huì)發(fā)生多態(tài)。

三、晚綁定原理:虛函數(shù)表

當(dāng)通過(guò)基類指針做虛函數(shù)調(diào)用時(shí)(即多態(tài)調(diào)用時(shí)),編譯器靜態(tài)地插入能取得這個(gè)VPTR并在VTABLE表中查找函數(shù)地址的代碼,這樣就能調(diào)用正確的函數(shù)并引起晚綁定的發(fā)生。編譯器會(huì)對(duì)每一個(gè)包含虛函數(shù)的類(或者從包含虛函數(shù)的基類派生的類)創(chuàng)建一個(gè)表(VTABLE),里面存放特定類的虛函數(shù)的地址。然后編譯器秘密地放置一指針vpointer(VPTR),指向這個(gè)對(duì)象的vtable。


學(xué)習(xí)教程快速掌握從入門到精通的電腦知識(shí)