c++真的是得工作若干年之後在回去重新梳理一遍基本概念纔會深深體會到大學時學到的只是皮毛。今天我們正真瞭解一下c++中什麼是覆蓋、隱藏和重載。
首先來看一下定義:
覆蓋:當子類中包含與父類中同名且參數列表相同的虛函數時,此時我們稱子類的虛函數覆蓋掉了父類的虛函數。
隱藏:當子類中包含與父類中同名且參數列表相同的非虛函數時,此時我們稱子類的函數隱藏了父類的函數。
重載:同一個類中函數名相同但是參數列表不相同時,我們稱此時類中發生成員函數重載。
上面三個定義中重載比較好理解也好區分,難點在與隱藏與覆蓋的區別。其實只要弄清楚隱藏發生在非虛函數中,而覆蓋發生在虛函數中就可以很輕鬆理解和區別了,同樣是子類中包含了與父類中同名的函數爲什麼包含虛函數叫覆蓋,包含非虛函數叫隱藏呢?我們知道在含有虛函數的內部還維護着一張虛函數表,當子類與父類的虛函數名相同時子類的虛函數會替換掉虛函數表中的同名函數從而導致無法在使用父類的該同名虛函數,所以叫覆蓋;而隱藏只是將父類的函數隱藏起來我們依然可以通過 "父類名::函數名" 這種方式訪問到父類的同名函數,所以叫隱藏。
下面我們通過一段代碼徹底梳理一下:
#include <iostream>
using namespace std;
class A
{
public:
A() {}
~A() {}
void fun1()
{
fun2();
fun3();
};
virtual void fun2()
{
cout << "fun2() at father class A" << endl;
};
void fun3()
{
cout << "fun3() at father class A" << endl;
}
private:
};
class B : public A
{
public:
B() {}
~B() {}
//覆蓋
virtual void fun2()
{
cout << "fun2() at son class B" << endl;
}
//隱藏
void fun3()
{
cout << "fun3() at son class B" << endl;
}
//重載
void fun3(int a)
{
cout << "fun3(int a) at son class B" << endl;
}
void fun4()
{
fun3();
fun3(5);
}
};
int main()
{
B b;
b.fun1();
b.fun4();
return 0;
}
首先我們自己先想象一下輸出,然後看看真正的輸出與你的理解是否一致,如果一致恭喜你,你已經徹底弄清楚在c++中什麼是覆蓋、隱藏和重載了:
還是再來強調一下,因爲fun2()是虛函數,它覆蓋掉了父類的fun2()虛函數,所以即便在父類本身的函數中我們也無法再調用到父類中的fun2()函數了,但是fun3()只是被隱藏了,所以當我們在父類的函數中調用fun3()依然調用的是父類中的fun3()因爲編譯器知道目前的上下文在父類中,並且父類的fun3()函數確實存在,所以會正確調用父類中的fun3()函數。