C++知識積累:過載、隱藏和重寫的區別
基本概念:
過載:是指同一可訪問區內被宣告的幾個具有不同引數列(引數的型別,個數,順序不同)的同名函式,根據引數列表確定呼叫哪個函式,過載不關心函式返回型別。
示例:
class A{
public:
void test(int a);
void test(double a);//過載
void test(int a, double b);//過載
void test(double a, int b);//過載
int test(int a); //錯誤,過載的返回型別必須相同
};
那麼這裡什麼叫做不關心函式返回型別呢?如下所示:
#include <iostream> using namespace std; class A { public: A(){}; ~A(){}; int test(int a,int b) {return a+b; } char test(int a) {return '5'+a; } }; int main() { A *a=new A(); cout << a->test(1) << endl; return 0; }
這裡呼叫一個引數的char test(int a)是完全可以的,但是如果過載函式為char test(int a,int b)的話,由於其引數列表與int test(int a,int b)相同,那麼就會提示char test(int a,int b)不能被過載,可想而知,在我們呼叫test這個函式的時候,如果以test(a,b)去呼叫,那系統又怎麼知道該呼叫int test(int a,int b)還是char test(int a,int b)呢?
由此我們也能看出,過載並非不能改變返回值型別,相反,只要合法,你可以隨意改變返回值型別,不過不管你是否改變返回值型別,你的過載函式的引數列表是必須改變的,換句話說,過載函式即是在函式名相同的情況下改變引數列表,函式返回型別是否更改並無影響,這也就是為什麼過載不關心函式返回型別了。
隱藏:是指派生類的函式遮蔽了與其同名的基類函式,注意只要同名函式,不管引數列表是否相同,基類函式都會被隱藏。
示例:
#include <iostream> using namespace std; class Base { public: void test(int a,int b){ cout << "Base called!" << endl; } }; class Derive : public Base { public: void test(int a){ cout << "Derive called!" << endl; } }; int main() { Derive d; d.test(1);// "Derive called!" 呼叫子類的fun函式 d.test(1, 1);// 錯誤,此時fun函式只能接收1個引數 return 0; }
也就是說,只要在子類中存在父類中的同名函式,那麼通過子類物件是無法呼叫父類相應的同名函式,只能呼叫當前子類的同名函式。
重寫(覆蓋):是指派生類中存在重新定義的函式。其函式名,引數列表,返回值型別,所有都必須同基類中被重寫的函式一致。只有函式體不同(花括號內),派生類呼叫時會呼叫派生類的重寫函式,不會呼叫被重寫函式。重寫的基類中被重寫的函式必須有virtual修飾。
示例:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void test(int a){ cout << "Base called !" << i << endl;}
};
class Derived : public Base
{
public:
virtual void test(int a){ cout << "Derived called! " << i << endl;}
};
int main()
{
Base b;
Base * pb = new Derived();
pb->test(3); // Derived called!
return 0;
}
總結一下:
過載、隱藏和重寫的區別:
(1)過載是對於同一類而言的,即過載函式與被過載的函式必須在同一類中;隱藏函式與被隱藏函式存在於不同類中;重寫與被重寫的函式是存在於父類與繼承類中,也就是在不同的類中。
(2)過載必須改變引數列表;隱藏既可以改變引數列表也可以不改變,如果隱藏函式不改變引數列表則相當於重寫;而重寫則不能改變引數列表,如果改變就相當於隱藏函數了。
(3)重寫函式的基類同名函式必須有virtual修飾,隱藏函式和被隱藏函式、過載函式和被過載函式都可以有virtual修飾,也可以沒有。
(4)如果子類中存在隱藏函式,那麼父類中被隱藏函式的所有過載函式都無法在子類中呼叫,但是仍然可以呼叫子類中的重寫函式。
如下所示:
#include <iostream>
using namespace std;
class A
{
public:
A(){};
~A(){};
virtual int test(int a,int b)
{
cout<<"A::int test(int a,int b) called!"<<endl;
return 0;
}
virtual char test(int a)
{
cout<<"A::char test(int a) called!"<<endl;
return '0';
}
};
class B:public A
{
public:
B(){};
~B(){};
int test(int a,int b,int c) //隱藏
{
cout<<"B::int test(int a,int b,int c) called!"<<endl;
return 0;
}
char test(int a) //重寫
{
cout<<"B::char test(int a) called!"<<endl;
return '0';
}
};
int main()
{
B b;
b.test(3,2,1); //"B::int test(int a,int b,int c) called!" 呼叫B中的test隱藏函式
b.test(1); //"B::char test(int a) called!" 呼叫B中的test重寫函式
return 0;
}