不知道大家有沒有聽說過函數隱藏!
見字面意思就是函數被隱藏,那麼爲什麼會被隱藏了?隱藏了又是什麼概念呢?
下面將通過一個例子講解!
例子是這樣的:
有一個單身Boy類,他有三個重載play的成員方法,分別是:
void play()
、 void play(string name)
、 void play(string name1, string name2)
;
他還有一個子類PlayBoy類,子類中,重寫了父類Boy類中的void play(string name1, string name2)
方法!然後main方法中調用這些方法而產生的一系列問題!!!
問題一:子類對象無法訪問父類的成員函數;
問題二:當子類沒有重寫父類的成員函數時,子類可以調用父類的成員函數;
我們先看代碼:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
// 定義Boy類
class Boy {
public:
// 父類的三個重載函數
void play() {
cout << "自己一個人玩!" << endl;
}
void play(string name) {
cout << "我和" << name << "一起看電影!" << endl;
}
void play(string name1, string name2) {
cout << "我和" << name1 << "、" << name2 << "一起做對人運動!" << endl;
}
};
// 定義PlayBoy類繼承與Boy類
class PlayBoy : public Boy {
public:
// 子類中重寫play(string name1, string name2)方法
void play(string name1, string name2) {
cout << "我和" << name1 << "、" << name2 << "一起喫雞!" << endl;
}
};
int main(void) {
PlayBoy* boy = new PlayBoy;
// 可以調用自己的成員方法
boy->play("小明", "小紅");
// 調用不了父類的其他成員方法
//boy->play("小明");
//boy->play();
system("pause");
return 0;
}
運行結果是這樣的:
然而如果我們調用父類的方法,就會提示報錯!
然而,當我們吧子類的重寫父類的play方法註釋後,卻沒有報錯,可以運行:
讓我們來看看運行結果:
看,真的沒問題,可以運行!!!
這是怎麼回事呢???
其實,當子類重寫父類的成員函數時,父類的成員函數對於子類對象來說,已經是隱藏的了,也就是在子類中已經沒有父類的成員函數的存在了。
舉一個例子:
一個公司,已經有了一套管理體系,而新的領導來報道後,如果他繼續沿用這套舊的管理體系,那麼對所有人都沒有影響;如果新的領導要重寫修改管理體系,那麼舊的管理體系就已經完全沒用了,只有新的管理體系在執行着!
轉換爲上面的代碼也是一樣的,如果子類繼承父類後沒有重寫父類的成員函數的話,那麼父類的成員函數,子類對象依舊可以調用;然而當子類重寫父類的成員函數後,父類的成員函數對於子類就已經沒用了,也就相當於被隱藏了!
這就是爲什麼子類重寫父類的成員函數後就調用不了父類的成員函數了!
當然,以上只是針對父類的重載函數起作用,對於父類其他的函數還是可以正常調用的!
不懂的,請看下面總結!
例如,我們在父類中加上一個函數void getPlay()
,那麼,子類一樣可以正常調用:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
// 定義Boy類
class Boy {
public:
// 父類的三個重載函數
void play() {
cout << "自己一個人玩!" << endl;
}
void play(string name) {
cout << "我和" << name << "一起看電影!" << endl;
}
void play(string name1, string name2) {
cout << "我和" << name1 << "、" << name2 << "一起做對人運動!" << endl;
}
// 父類的其他函數
void getPlay() {
cout << "開黑一直爽,一直開黑一直爽!" << endl;
}
};
// 定義PlayBoy類繼承與Boy類
class PlayBoy : public Boy {
public:
// 子類中重寫play(string name1, string name2)方法
void play(string name1, string name2) {
cout << "我和" << name1 << "、" << name2 << "一起喫雞!" << endl;
}
};
int main(void) {
PlayBoy* boy = new PlayBoy;
//Boy* boy = new PlayBoy;
boy->play("小明", "小紅");
// 可以正常調用,沒有報錯
boy->getPlay();
//boy->play("小明");
//boy->play();
system("pause");
return 0;
}
運行結果:
好了,那麼我們該如何解決以上遇到的問題呢?
有兩個解決辦法:
第一:使用父類指針指向子類對象:Boy* boy = new PlayBoy;
第二:調用父類函數時,使用強制類型轉換:((Boy *)boy)->play("小明");
int main(void) {
//PlayBoy* boy = new PlayBoy;
/*
* 方法一: 使用父類指針指向子類對象
*/
Boy* boy = new PlayBoy;
boy->play("小明", "小紅");
// 可以正常調用,沒有報錯
//boy->getPlay();
/*
* 方法二: 使用強制類型轉換
*/
((Boy *)boy)->play("小明");
((Boy*)boy)->play();
system("pause");
return 0;
}
運行結果:
總結:
子類實現某函數後,從父類繼承的函數,只要函數名相同,無論是否同參,無論是否是虛函數,使用子類指針訪問,只能訪問到子類重寫的函數,父類的同名函數都被隱藏;
使用父類指針訪問:
- 對於虛函數:只能訪問到子類重寫的函數
- 非虛函數:只能訪問到父類的函數