【转】c++重载、覆盖、隐藏——理不清的区别
生活随笔
收集整理的這篇文章主要介紹了
【转】c++重载、覆盖、隐藏——理不清的区别
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文網址:http://blog.sina.com.cn/s/blog_492d601f0100jqqm.html
再次把林銳博士的《高質量c++編程指南》翻出來看的時候,再一次的覺得這是一本難得的好書。實踐派寫的東西跟理論派和翻譯派寫的書有著本質的 區別,每次讀這本書都覺得為什么自己讀了這么多遍,還是會犯一些上面講的小錯誤,編代碼有時候莫名其妙又會把自己轉糊涂了。這本書淺顯易懂,而且提到了編 程過程中應該注意的很多細節,里面展開來講的細節又偏偏是我覺得最為薄弱的環節,如果大家想學或者正在學習c++。建議大家用心的把這本并不長也不高深的 書好好的讀幾遍。
關于c++語言中重載、覆蓋、隱藏這三個容易混淆的概念,我依然以林博士書中的例子發散開來回憶一下。先列舉這三個概念必須滿足的條件: 函數重載的特征: 1)處在相同的空間中(即相同的作用范圍內,比如一個類中)。 2)函數名相同。 3)參數不同(相同位置參數的類型不同,或者參數的個數不同)。 4)virtual關鍵字可有可無。 覆蓋的特征: 1)不同的范圍(例如分別位于基類與派生類)。 2)函數名相同。 3)參數相同(參數個數與類型均相同)。 4)基類函數必須有virtual關鍵字(派生類可有可無,因為基類函數被聲明為虛函數,派生類同名函數一定也是虛函數)。 隱藏的特征: 1)不同的范圍(例如分別位于基類與派生類)。 2)函數名相同。 3)參數可相同也可不同(注意此處還有兩種情況)。 4)virtual關鍵字可有可無。 注意:隱藏與覆蓋的區別就在于如下兩條: 1)如果派生類的函數與基類的函數同名,但是參數不同(不可能構成覆蓋)。此時無論有無virual關鍵字,基類的函數將被隱藏。(不可能構成重載,因為重載必須在同一個類中) 2)如果派生類的函數與基類的函數同名,并且參數也相同,但是基類函數沒有virual關鍵字(如果有virual關鍵字,則滿足覆蓋的條件)。此時基類的函數被隱藏。 隱藏: 下面是林博士原書中的例子: #include <iostream.h> class Base { public: void g(float x){cout << "Base::g(float)" << x <<endl;}???????//注意c++中將在類聲明中定義了實現的函數自動默認為內聯函數 void h(float x){cout << "Base::h(float)" << x <<endl;} } class Derived : public Base { public: void g(int x){cout << "Derived::g(int)" << x <<endl;}?????? void h(float x){cout << "Derived::h(float)" << x <<endl;} } void main(void) { Derived d Base* pb = &d; Derived* pd = &d; //behavior depends on type?of pointer pb->g(3.14f);?????//Base::g(float) 3.14; pd->g(3.14f);?????//Derived::g(int) 3; pb->h(3.14f);?????//Base::h(float) 3.14; pd->h(3.14f);?????//Derived::h(float) 3.14; } 參照隱藏規則,派生類的成員函數隱藏了基類的同名函數。所謂隱藏就是指派生類類型的對象、引用、指針訪問基類和派生類都有的同名函數的時候,訪問的是派生 類的函數,隱藏了基類同名函數。派生類既然自動繼承了基類的成員,那么基類成員就可以被派生類直接訪問,那么為什么訪問的是派生類的成員函數呢?所以隱藏 規則實際上就是默認的c++名字解析過程。 在繼承機制下,派生類的類域被嵌套在基類的類域中,派生類的名字解析過程如下: 1)首先在派生類中查找改名字。 2)如果第一步未查找到,及派生類的類域對改名字無法進行解析,則編譯器在外圍基類類域查找改名字的定義。 所以準確來說,當派生類和基類有同一名字的成員時,派生類成員是隱藏了對基類成員的直接訪問。那么如果訪問到基類同名成員呢?加上類作用域限定例如:Base::g(float)就可以訪問了。 覆蓋: 覆蓋規則造成的調用現象,其實就是類的虛函數實現原理生成的。為了達到動態綁定(后期綁定)的目的,C++編譯器通過某個表格(一般稱為vtable), 在執行期"間接"調用實際上欲綁定的函數。每一個內含虛函數的類,C++編譯器都會為它做出一個虛函數表,表中的每一個元素都指向一個虛函數的地址。??
???舉個例子:
????class base{
????public:
????????func();
????????virtual vfunc1();
????????virtual vfunc2();
????????virtual vfunc3();
????private:
????????int _data1;
????????int _data2;
????};
????base對象實例在內存中占據的空間是這樣的:
?????base對象實例??????????vtable
--------------------------------------------------------------------------
?????????vptr ---------> (*vfunc1)() -----------> base::vfunc1();
????????_data1???????????(*vfunc2)() -----------> base::vfunc2();
????????_data2???????????(*vfunc3)() -----------> base::vfunc3();
--------------------------------------------------------------------------
?
????當派生類改寫了虛函數時,虛函數表相應的被修改了:
????class derived: public base{
????public:
????????vfunc2();
????};
????derived對象實例??????????????vtable
--------------------------------------------------------------------------
?????????vptr??---------> (*vfunc1)() -----------> base::vfunc1()??????
????????_data1;???????????(*vfunc2)() -----------> derived::vfunc2()?????****注意,這里變了!!!***
????????_data2;???????????(*vfunc3)() -----------> base::vfunc3()
--------------------------------------------------------------------------
?
????所以當你寫下如下程序的時候:
????void main(void)
????{
????????Derived d;
????????Base *pb = &d;
????????pb->vfunc2(); // Derived::vfunc2(void)
????}?
????就不難理解為何pb->vfunc2()調用的是derived::vfunc2()了,因為pb實際上指向派生類derived的實例,而派生類中的虛函數表已經被修改了。
?
????總結:簡單來說,隱藏規則就是C++的名字解析過程,自里向外解析,這個好理解;而覆蓋規則其實就是C++虛函數表的實現原理。
總結
以上是生活随笔為你收集整理的【转】c++重载、覆盖、隐藏——理不清的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宇宙、事象
- 下一篇: 一条命令monkey命令