C++中重載、覆蓋和多態是三個有些相似的概念,以下以代碼的方式展示三者的不同。
1)重載:同名函數不同參數(類型、個數),編譯時編譯器確定使用哪個函數,屬於編譯時“多態”,不是真正的多態;
2)覆蓋:子類覆蓋父類的虛函數,函數名、參數必須相同。覆蓋需要滿足兩個條件,繼承父類的虛函數和使用父類的指針(或引用)綁定子類實例。由覆蓋產生的多態是運行時多態,編譯時無法確定具體調用那個函數,是真正的多態;
3)隱藏:父類與子類中同名函數的一種處理機制,同一個子類的函數可以同時覆蓋父類的函數並且隱藏父類的某些函數。
/**這個工程主要研究C++中的重載、覆蓋和隱藏三個相似的概念*/
#include <iostream>
#include <string>
using namespace std;
void fun(int i)
{
cout << "int: " << i << endl;
}
//int fun(int i) //錯誤,不能根據返回值來對函數進行重載!
//{
// cout << i << endl;
//}
void fun(float i)
{
cout << "float: " << i << endl;
}
void fun(int *p)
{
cout << "pointer: " << *p << endl;
}
void fun(const int *p) //正確,low level的const可以作爲重載的依據!
{
cout << "const pointer: " << *p << endl;
}
//void fun(int* const p) //錯誤,top level的const不能作爲重載依據!
//{
// cout << *p << endl;
//}
class Base
{
public:
virtual void fun1(int i)
{
cout << "Base int: " << i << endl;
}
void fun1(float i) //與上一個fun1構成重載關係
{
cout << "Base float: " << i << endl;
}
void fun2(int i, int j)
{
cout << "Base i j: " << i + j << endl;
}
};
class Derived : public Base
{
public:
void fun1(int i) override //覆蓋了virtual void fun1(int i),同時隱藏了void fun1(float i);override(C++11)關鍵字保證該函數覆蓋了父類的某個函數!
{
cout << "Derived int: " << i << endl;
}
void fun1(string str) //隱藏了父類的fun1,並且與子類的fun1形成重載
{
cout << "Derived string: " << str << endl;
}
void fun2(float i) //隱藏了父類的fun2
{
cout << "Derived float: " << i << endl;
}
};
int main()
{
/**1: 重載,重載的概念比較簡單,函數名相同,參數類型(或個數)不同即可構成重載。
但重載要注意兩點,第一函數返回值不能作爲重載依據,第二top-level的const不能作爲重載依據。
top-level的const指對象本身是const,而low-level的const值該對象指向的對象是const。
重載的根本依據就是編譯器是否可以根據函數的參數來區分不同的函數。*/
int i = 0, *p = &i;
const int *cp = &i;
float f = 0.5;
fun(i);
fun(f);
fun(p);
fun(cp);
/**2: 覆蓋,覆蓋發生在子類與父類之間。覆蓋必須滿足1)父類定義virtual函數;2)子類中有同名、同參數函數。
覆蓋於重載的重要區別是重載是編譯時“多態”,而覆蓋是運行時多態(真正的多態),也就是說只有在運行時
才能確定使用哪個函數。*/
Base b;
b.fun1(1);
Derived d;
d.fun1(1);
Base &bd = d;
bd.fun1(1);
/**3: 隱藏,隱藏也發生在子類和父類之間。子類與父類的同名函數到底是隱藏還是覆蓋由兩點決定:
1)無virtual,同名即隱藏(無論參數相同或不同);
2)有virtual,同名不同參數是隱藏,同名相同參數是覆蓋。*/
d.fun1(0.5); //無法調用父類的float的版本,只能調用子類的int版本!
d.fun1("abc");
//d.fun2(1, 2); 錯誤,子類的fun2隱藏了父類的fun2,無法使用父類的fun2!
d.Base::fun2(1, 2); //可以顯示的調用父類的函數。
return 0;
}