c++ 過載、覆蓋、隱藏差異
1.成員函式過載(overload)的特徵:
(1)相同的範圍(在同一個類中);
(2)函式名字相同;
(3)引數不同;
(4)virtual關鍵字可有可無。
(5)返回值可以不同
總之,函式過載與否看的是函式引數的個數、型別以及順序
2.覆蓋(override)(重寫)是指派生類函式覆蓋基類函式,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有virtual關鍵字。
(5)返回值相同,否則報錯;
(6)覆蓋函式的訪問修飾符可以不同;(private到public及其他)
重新定義一個基類中的過載函式將會隱藏所有該函式的其他基類版本。
3.重定義(redefining)(也成為隱藏)是指派生類的函式遮蔽了與其同名的基類函式,規則如下:
(1)不在同一作用域(分別位於派生類與基類)
(2)函式名相同;
(3)返回值可以不同;
(4)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。
(5)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。
函式過載(overload)含義相對好理解,主要是重定義(redefining隱藏)與覆蓋(override重寫)容易混淆。
總結:
覆蓋(override重寫)是針對基類虛擬函式(Virtual)而言的,在派生類中除了訪問修飾符可以不同外,函式名、返回值和引數列表都要相同。
重定義(redefining也稱為隱藏),在派生類中除了函式名要相同外,其他(返回值、引數表、訪問屬性)都可不同。
另外有句話很重要:指標是什麼型別,則指標呼叫的函式就是指標型別的函式(除了覆蓋,這種情況)。
例如:Derive a; Base *p=&a;p->func();這裡如果func()函式在基類中是虛擬函式,且在派生類中覆蓋了這一函式,則p->func()呼叫的就是派生類的函式,否則呼叫的就是基類的func()函式,不論派生類是否重定義func()函式。
#include<iostream>
#include<string>
using namespace std;
class Base
{
private:
virtual void display()
{
cout<<"Base display()"<<endl;
}
public:
void say()
{
cout<<"Base say()"<<endl;
}
public:
void exec()
{
display();//覆蓋;
say();//重定義(Redefining隱藏);
}
private:
void fun1(string a) {cout<<"Base fun1(string)"<<endl;}
void fun1(int a) {cout<<"Base fun1(int)"<<endl;}//overload,兩個fun1函式在Base類的內部被過載
};
class ChildA:public Base
{
public:
//override,基類中的display函式引數列表,函式名相同且有virtual修飾為虛擬函式,故此處為重寫(覆蓋);
void display( )
{
cout<<"ChildA display()"<<endl;
}
//redefining,fun1函式與基類的函式同名但引數列表不同,故為重定義;
void fun1(int a,int b) {cout<<"ChildA fun1(int,int)"<<endl;}
//redefining,say函式與基類函式同名,引數列表一樣,但基類函式沒有virtual修飾,故為重定義;
void say()
{
cout<<"ChildA say()"<<endl;
}
};
class ChildB:public Base
{
public:
//redefining,與基類中fun1函式名、引數列表相同,但基類函式沒有virtual修飾,故為重定義;
//重定義函式的返回型別可以不同;
int fun1(double a)
{
cout<<"ChildB fun1(double)"<<endl;
return 0;
}
};
int main()
{
ChildA a;
Base* b= &a;
//display():version of DeriveA call(polymorphism)
//say():version of Base called(allways )
b->exec();
//b裡邊的函式display被A類重寫(覆蓋),say還是自己的;
//什麼指標就呼叫什麼函式;
b->say();
a.exec(); //same result as last statement
a.say();
ChildB c;
c.fun1(1.1); //version of ChildB called
}