寫這篇文章的時候我還是不太確定重定義,重寫(覆蓋),重載之間的確切的區分方法。下面是我今天的理解以及相關測試代碼,以待後觀!!
第一:簡單的子類重定義父類成員函數(函數三要素:返回類型,函數名,參數):既然是重定義,函數名肯定是相同的,不然就沒有必要討論了。三要素都相同,自然可以成立,現在的問題是返回類型和參數是不是可以隨意給,同樣能隱藏父類的成員函數?
(1)函數名,返回類型,參數都相同
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a){
cout << "父類" << endl;
}
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;//第一種情況,函數名,返回類型,參數都相同
}
};
int main()
{
CDerivedA ptr;
ptr.my(5);
system("pause");
return 0;
}
上面結果爲調用子類成員函數輸出:子類
(2)函數名,返回類型相同,參數不同,
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a,int b){
cout << "父類" << endl;
}
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;//參數個數不同
}
};
int main()
{
CDerivedA ptr;
ptr.my(5);//(1)給出一個參數
ptr.my(5,5);//(2)給出兩個參數,此時會報錯,函數不接受兩個參數。說明這個時候,子類並沒有繼承到父類void my(int a,int b)函數。
system("pause");
return 0;
}
一個參數的時候,調用子類的成員函數,輸出爲:子類。兩個參數的時候報錯,說明基類方法已經被隱藏了(重新定義繼承函數,原來的函數被隱藏)。
(3)重定義繼承方法,應確保與原來的原型完全一致——返回類型協變
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a,int b){
cout << "父類" << endl;
}
virtual void Walk(){ cout << "CBase:Walk" << endl; }
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;
}
int Walk(){ cout << "CDerivedA:Walk" << endl; }//重定義類型與原來的類型不同
};
int main()
{
CDerivedA ptr;
ptr.Walk();
system("pause");
return 0;
}
輸出結果報錯:重寫虛函數返回類型有差異,且不是來自“CBase::Walk”的協變
第二:虛函數重寫(覆蓋)(返回值類型必須相同)
(1)參數列表相同
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a,int b){
cout << "父類" << endl;
}
virtual void Walk(){ cout << "CBase:Walk" << endl; }
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;
}
void Walk(){ cout << "CDerivedA:Walk" << endl; }//重寫
};
int main()
{
CDerivedA ptr;
ptr.Walk();//輸出結果爲:CDerivedA:Walk
system("pause");
return 0;
}
這是最常見的對父類虛函數重寫
參數列表不同
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a,int b){
cout << "父類" << endl;
}
virtual void Walk(int a){ cout << "CBase:Walk" << endl; }
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;
}
void Walk(){ cout << "CDerivedA:Walk" << endl; }//重寫
};
int main()
{
CDerivedA ptr;
ptr.Walk(2);//報錯:函數不接受 1 個參數
ptr.Walk();//輸出:CDerivedA:Walk
system("pause");
return 0;
}
對虛函數重新定義,但是由於參數列表不同,很容易理解爲函數重載。如果是函數重載,那麼子類對象 應該繼承了父類被重載的成員函數,ptr.Walk(2);就不應該報錯。這說明,在這裏還是重定義,父類中同名函數被隱藏。
第三:父類重定義函數
#include <iostream>
using namespace std;
class CBase
{
public:
void my(int a,int b){
cout << "父類" << endl;
}
virtual void Walk(int a){ cout << "CBase:Walk" << endl; }
virtual void Walk(){ cout << "CBase::::::Walk" << endl; }
};
class CDerivedA : public CBase
{
public:
void my(int a ){
cout << "子類" << endl;
}
//void Walk(){ cout << "CDerivedA:Walk" << endl; }//重寫
};
int main()
{
CDerivedA ptr;
ptr.Walk(2);//輸出:CBase:Walk
ptr.Walk();//輸出:CBase::::::Walk
system("pause");
return 0;
}
結論:子類不能重載父類函數。即,重載發生在同一個類裏面
結論:
在類繼承中,重定義,重載。重定義函數名相同,返回類型必須相同,參數列表可以相同,可以不同;重載,函數名相同,返回類型和參數列表至少一個不同。
只要子類出現與父類同名的函數,子類就不會繼承父類同名函數(隱藏)。當該同名函數在父類聲明爲虛函數時(virtual),稱爲重寫(覆蓋),非虛函數時,稱爲重定義