一.結(jié)論
二.詳細說明
為了說明以上的結(jié)論,首先需要說明隱藏、覆蓋以及作用域等概念,接著舉例說明隱藏、覆蓋以及作用域等帶來的問題,最后以解決方法解決以上問題。
2.1 隱藏、覆蓋和作用域
作用域:從字面上理解,某事物起作用的地方,比如說白天太陽能夠照射的地方,能看到太陽,而照不到的地方就看不到太陽,能夠看到太陽的地方就是太陽的作用域。比較官方的定義如下:
作用域:程序設(shè)計概念,通常來說,一段程序代碼中所用到的名字并不總是有效/可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域 —百度百科
隱藏:從字面上理解就是,因為某事物的到來,一些事物被隱藏起來了,但是可以通過一些辦法讓它顯現(xiàn)出來,比如還以上面的例子,太陽照射不到的地方通過鏡子將陽關(guān)反射到被隱藏事物的地方(轉(zhuǎn)調(diào)),隱藏的事物亦可以看到太陽了。官方的定義:
派生類將繼承的基類的同名的成員變量和成員方法隱藏起來,通過派生類只能訪問到自己的成員變量和成員方法。
覆蓋: 從字面上理解,某些事物因為有沖突,在一些作用域下不能同時出現(xiàn),在某一片陽光下,要么只能出現(xiàn)事物A,要么只能出現(xiàn)事物B。
覆蓋往往與繼承的類中有virtual修飾的函數(shù)有關(guān)。virtual修飾的函數(shù)為虛函數(shù)。而覆蓋就是基類中有virtual修飾的函數(shù),且在派生類中有與基類中的虛函數(shù)同名且同參數(shù)列表的函數(shù),那么派生類中的的該函數(shù)就會將基類中的函數(shù)覆蓋,調(diào)用時無法調(diào)用基類中的函數(shù)
2.2.局部變量和全局變量選擇
int val = 1; // global valuevoid main(){ double val = 2.5; // local value std::cout << val << std::endl; // out 2.5 std::cout << ::val << std::endl; // out 1}
運行結(jié)果:
2.51
當編譯器在cout處輸出val時,將首先查找 TestFun 的作用域中是否有名字 val ,如果有則它將直接輸出這個變量的值,如果沒有則會向TestFun之外的地方查找val符號,找到則直接輸出。此處輸出2.5,局部的val變量覆蓋了全局的val變量。如果要想使用全局變量val,需要添加作用域::val。
此處局部變量掩蓋全局變量,若想使用全局變量可添加作用域的形式使用
2.3. 繼承時變量選擇
有如下類繼承關(guān)系,基類中包含純虛函數(shù)、虛函數(shù)和非虛函數(shù),派生類公有繼承基類,包含基類中非虛函數(shù)的同名同參函數(shù)和獨有函數(shù),如下:
class Base {private: int val; public: virtual void mFun1() = 0; virtual void mFun1(double) { std::cout << "Base mFun1 with param double" << std::endl; } virtual void mFun2() { std::cout << "Base mFun2" << std::endl; } void mFun3() { std::cout << "Base mFun3" << std::endl; } void mFun3(float) { std::cout << "Base mFun3 with param float" << std::endl; }};class Derived: public Base {public: virtual void mFun1() { std::cout << "Derieved mFun1" << std::endl; } void mFun3() { std::cout << "Derieved mFun3" << std::endl; mFun2(); } void mFun4() { std::cout << "Derieved mFun4" << std::endl; mFun3(); // mFun3(1.25); // no matching function }};
1.在構(gòu)建派生類實例時,調(diào)用同名同參的非虛函數(shù)mFun3時,其搜索路徑是,先搜索mFun3內(nèi)部是否找到mFun2,如果沒有找到則在類Derived中查找mFun2,如果類內(nèi)有找到則繼續(xù)向上Base類中查找mFun2,如果沒有找到則繼續(xù)向本文件中查找mFun2等等。此處mFun2在Base類中找到,如下例子:
int main() { Derived der; der.mFun3(); return 0;}
運行結(jié)果:
Derieved mFun3Base mFun2
2.在構(gòu)建派生類實例時,調(diào)用函數(shù)mFun4時,mFun4中現(xiàn)調(diào)用的mFun3只會調(diào)用派生類Derived中的mFun3,且無法調(diào)用帶參數(shù)的mFun3,否則編譯時會報no matching function錯誤,實例中調(diào)用帶參的mFun3一樣報錯,因為派生類中的函數(shù)覆蓋了基類中的同名函數(shù)包括不同參數(shù),換句話說派生類中的同名函數(shù)覆蓋了了Base::mFun1和Base::mFun3。 如下例子:
int main() { Derived der; der.mFun1(); // call Derived mFun1 der.mFun4(); // call Derived mFun4 // der.mFun3(1.25); // no matching function return 0;}
運行結(jié)果
Derieved mFun4Derieved mFun3Base mFun2
從上面的兩個例子中可以發(fā)現(xiàn)一個很明顯的問題,由于同名覆蓋的情況,導致在派生類中無法調(diào)用基類中同名不同參數(shù)的函數(shù), 以下就是一些解決辦法
2.4 使用using聲明
使用using 聲明可以將作用域從原先限定的地方拓展到聲明的地方,增加其使用范圍,例子如下:
// Base基類同上class Derived: public Base {public: using Base::mFun3; virtual void mFun1() { std::cout << "Derieved mFun1" << std::endl; } void mFun3() { std::cout << "Derieved mFun3" << std::endl; mFun2(); } void mFun4() { std::cout << "Derieved mFun4" << std::endl; mFun3(); // mFun3(1.25); // no matching function }};
使用Demo進行測試:
int main() { Derived der; der.mFun1(); // call Derived mFun1 der.mFun1(1.0); // call Base mFun1 der.mFun4(); // call Derived mFun4 der.mFun3(); // call Derived mFun3 der.mFun3(1.25); // call Base mFun3 return 0;}
運行結(jié)果:
Derieved mFun1 // der.mFun1();Base mFun1 with param double // der.mFun1(1.0);Derieved mFun4 // der.mFun4();Derieved mFun3Base mFun2Derieved mFun3 // der.mFun3();Base mFun2Base mFun3 with param float // der.mFun3(1.25);
從結(jié)果中可以看出使用using聲明將基類中的函數(shù)作用域拓展到了派生類中,在派生類中可以直接使用,假如派生類中只想繼承基類中不帶參數(shù)的函數(shù)該如何呢?這時使用using聲明可能會將帶參數(shù)的函數(shù)同時給引入進來,而無法解決此類問題。此處可以通過轉(zhuǎn)調(diào)函數(shù)實現(xiàn),如下。
2.5 使用轉(zhuǎn)掉函數(shù)
私有繼承加上轉(zhuǎn)調(diào)函數(shù)可以完美解決using聲明不能解決的只繼承帶不參數(shù)的函數(shù),例子如下:
// Base基類同上void Base::mFun1(){ std::cout << "Base mFun1" << std::endl;}class Derived: private Base {public: virtual void mFun1() { std::cout << "Derieved mFun1" << std::endl; Base::mFun1(); }};
使用Demo進行測試
int main() { Derived der; der.mFun1(); // call Derived mFun1 // der.mFun1(1.0); // error no matching function return 0;}
運行結(jié)果:
Derieved mFun1Base mFun1
參考:
1.Effective C++ Item33
2.解析C++隱藏與覆蓋Oragen的博客-CSDN博客c++隱藏和覆蓋
3.作用域_百度百科 (baidu.com)
備注:
歡迎大家多多指教,喜歡的大家可以點擊關(guān)注本賬號或者微信公眾號:軟件系統(tǒng)安全,后續(xù)將不定期更新C++相關(guān)的內(nèi)容