1. 程式人生 > >C++中函式過載、隱藏、覆蓋和重寫的區別 轉自:http://www.bijishequ.com/detail/277975?p=

C++中函式過載、隱藏、覆蓋和重寫的區別 轉自:http://www.bijishequ.com/detail/277975?p=

程式碼編譯執行環境:VS2012+Debug+Win32

1.函式過載(Function Overload)

1.1定義

C++規定在同一作用域中,同名函式的形式引數(指引數的個數、型別或者順序)不同時,構成函式過載。

1.2用法

比如,要從兩個變數中返回其中較大的一個值,可以編寫如下兩個構成過載的函式。

int max(int a,int b){
return a>b?a:b;
};

double max(double a,double b){
return a>b?a:b;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1.3注意事項

(1)函式返回值型別與構成函式過載無任何關係; 
(2)類的靜態成員函式與普通成員函式可以形成過載; 
(3)函式過載發生在同一作用域,如類成員函式之間的過載、全域性函式之間的過載。

2.函式隱藏(Function Hiding)

2.1定義

函式隱藏指不同作用域中定義的同名函式構成函式隱藏(不要求函式返回值和函式引數型別相同)。比如派生類成員函式遮蔽與其同名的基類成員函式、類成員函式遮蔽全域性外部函式。請注意,如果在派生類中存在與基類虛擬函式同返回值、同名且同形參的函式,則構成函式重寫。

2.2用法用例

請仔細研讀以下程式碼。

#include <iostream>
using namespace std;

void func(char* s){
cout<<"global function with name:"<<s<<endl;
}

class
A{ void func(){ cout<<"member function of A"<<endl; } public: void useFunc(){ //func("lvlv");//A::func()將外部函式func(char*)隱藏 func(); ::func("lvlv"); } virtual void print(){ cout<<"A's print"<<endl; } }; class B:public A{ public: void useFunc(){ //隱藏A::vodi useFunc() cout<<"B's useFunc"
<<endl; } int useFunc(int i){ //隱藏A::vodi useFunc() cout<<"In B's useFunc(),i="<<i<<endl; return 0; } virtual int print(char* a){ cout<<"B's print:"<<a<<endl; return 1; } //下面編譯不通過,因為對父類虛擬函式重寫時,需要函式返回值型別,函式名稱和引數型別全部相同才行 // virtual int print(){ // cout<<"B's print:"<<a<<endl; // } }; int main(){ A a; a.useFunc(); B b; b.useFunc();//A::useFunc()被B::useFunc()隱藏 b.A::useFunc(); b.useFunc(2); //b.print();//編譯出錯,A::print()被B::print(char* a)隱藏 b.A::print(); b.print("jf"); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

程式執行結果: 
這裡寫圖片描述

2.3注意事項

對比函式隱藏與函式過載的定義可知: 
(1)派生類成員函式與基類成員函式同名但引數不同。此時基類成員函式將被隱藏(注意別與過載混淆,過載發生在同一個類中); 
(2)函式過載發生在同一作用域,函式隱藏發生在不同作用域。

3.函式覆蓋與函式重寫(Function Override)

網上和很多書籍多都會涉及函式覆蓋的概念,眾說紛紜,加大了許多初學者的學習難度,甚至產生誤導。事實上,函式覆蓋就是函式重寫。

3.1定義

派生類中與基類同返回值型別、同名和同引數的虛擬函式重定義,構成虛擬函式覆蓋,也叫虛擬函式重寫。

關於返回值型別存在一種特殊情況,即協變返回型別(covariant return type)。

3.2虛擬函式重寫與協變返回型別

如果虛擬函式函式返回指標或者引用時(不包括value語義),子類中重寫的函式返回的指標或者引用是父類中被重寫函式所返回指標或引用的子型別(這就是所謂的協變返回型別) [4] [Math Processing Error]。看示例程式碼:

#include <iostream>
using namespace std;

class A{}; 
class B:public A{};

class Base{
public:
virtual A& show(){
cout<<"In Base"<<endl;
return *(new A);
}
};

class Derived:public Base{
public:
//返回值協變,構成虛擬函式重寫
B& show(){
cout<<"In Derived"<<endl;
return *(new B);
}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3.3注意事項

(1)函式覆蓋就是虛擬函式重寫,而不是函式被”覆蓋”。 
從上面的程式碼可以看出,函式是不可能被“覆蓋”的。有些人可能會錯誤地認為函式覆蓋會導致函式被”覆蓋”而”消失”,將不能被訪問,事實上只要通過作用域運算子::就可以訪問到被覆蓋的函式。因此,不存在被”覆蓋“的函式。

(2)函式覆蓋是函式隱藏的特殊情況。 
對比函式覆蓋和函式隱藏的定義,不難發現函式覆蓋其實是函式隱藏的特例。

如果派生類中定義了一個與基類虛擬函式同名但引數列表不同的非virtual函式,則此函式是一個普通成員函式(非虛擬函式),並形成對基類中同名虛擬函式的隱藏,而非虛擬函式覆蓋(重寫)。

《C++高階進階教程》中認為函式的隱藏與覆蓋是兩個不同的概念。隱藏是一個靜態概念,它代表了識別符號之間的一種遮蔽現象,而覆蓋則是為了實現動態聯編,是一個動態概念。但隱藏和覆蓋也有聯絡:形成覆蓋的兩個函式之間一定形成隱藏。例如,可以對虛擬函式採用“實呼叫”,即儘管被呼叫的是虛擬函式,但是被呼叫函式的地址還是在編譯階段靜態確定的,那麼派生類中的虛擬函式仍然形成對基類中虛擬函式的同名隱藏。

參考如下程式碼,考察虛擬函式的實呼叫和虛呼叫。

#include <iostream>
using namespace std;

class Base{
public:
virtual void show(){
cout<<"In Base"<<endl;
}
};

class Derived:public Base{
public:
void show(){
cout<<"In Derived"<<endl;
}
};

int main(){
Base b;
b.show();
Derived d;
d.show(); //對函式show()的實呼叫
d.Base::show(); //對函式show()的實呼叫
Base *pb=NULL; 
pb=&d; 
pb->show(); //對函式show()的虛呼叫
pb->Base::show(); //對函式show()的實呼叫
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

程式執行結果: 
In Base 
In Derived 
In Base 
In Derived 
In Base

4.總結

在討論相關概念的區別時,抓住定義才能區別開來。C++中函式過載隱藏和覆蓋的區別,並不難,難就難在沒弄清定義,被網上各種說法弄的雲裡霧裡而又沒有自己的理解。

在這裡,牢記以下幾點,就可區分函式過載、函式隱藏、函式覆蓋和函式重寫的區別: 
(1)函式過載發生在相同作用域; 
(2)函式隱藏發生在不同作用域; 
(3)函式覆蓋就是函式重寫。準確地叫作虛擬函式覆蓋和虛擬函式重寫,也是函式隱藏的特例。

關於三者的對比,李健老師在《編寫高質量程式碼:改善C++程式的150個建議》給出了較為詳細的總結,如下表所示:

三者 作用域 有無virtual 函式名 形參列表 返回值型別
過載 相同 可有可無 相同 不同 可同可不同
隱藏 不同 可有可無 相同 可同可不同 可同可不同
重寫 不同 相同 相同 相同(協變)



本文為個人觀點,歡迎留言批評指正。

參考文獻

[1]陳剛.C++高階進階教程[M].第一版.武漢:武漢大學出版社,2008:110-P112 
[2]百度百科.函式隱藏 
[3]李健.編寫高質量程式碼:改善C++程式的150個建議.第一版.北京:機械工業出版社,2012.1:122-125 
[4]C++基礎:函式重寫(override)與協變返回型別(covariant return type)