繼承&多態ios
· 訪問限定符ide
*繼承訪問控制的做用是將繼承下來的成員在派生類域內的屬性改變而和本來基類的成員訪問控制符關。函數
全部的基類private成員在派生類裏是不可見,但它確確實實被繼承下來了。url
基類的protected成員只對繼承它的派生類可見,在類外不可以使用spa
· 派生類列表指針
在定義派生類的時候咱們必須寫出派生類列表,但在聲明處不可寫。調試
1.虛函數的使用(多態的實現)對象
#include<iostream> using namespace std; class Base { private: int _base ; public: Base() :_base (0) {} virtual void show() { cout << "Base::show()" << endl ; } //.... }; class D :public Base { public: D() :_d (1) {} void show() { cout << "D::show()" << endl ; } private: int _d ; }; void Print (Base *pb) { pb-> show(); } int main () { Base b; D d; Print(& b); Print(& d); getchar(); return 0; }
*經過傳參的不一樣使得show函數的輸出結果不一樣,實現的原理是:虛函數表(動態綁定)blog
*動態綁定:函數的運行版本由實參決定,在函數運行時才進行選擇,又稱運行時綁定繼承
*規則:基類一般都須要定義一個虛析構函數,不管是否在後面用到
*成員函數若是沒有被聲明爲虛函數而且不是靜態函數,那它的解析過程發生在編譯階段而不是運行階段
*每一個類控制本身的成員初始化,不要使用派生類直接初始化基類成員
*派生類必須對它內部從新定義的虛函數進行聲明
*任何除了構造函數之外的非靜態函數均可以是虛函數
2.虛函數表
a.單繼承
如上例中代碼示,單繼承時Base的對象模型以下
D的對象模型以下
b.多繼承
#include<iostream> using namespace std; typedef void (*PTR)(); class Base { private: int _base ; public: Base() :_base (0) {} virtual void show() { cout << "Base::show()" << endl ; } //... }; class Base2 { private: int _base2 ; public: Base2() :_base2 (2) {} virtual void show() { cout << "Base2::show()" << endl ; } virtual void fun2() { cout << "Base2::fun2()" << endl ; } //... }; class D :public Base,public Base2 { public: D() :_d (1) {} void show() { cout << "D::show()" << endl ; } void fun2() { cout << "D::fun2()" << endl ; } virtual void fun3() { cout << "D::fun3()" << endl ; } virtual void fun4() { cout << "D::fun4()" << endl ; } private: int _d ; }; void PrintVT (int p ) //實參是每一個類存儲虛函數指針的地址,解引用以後表明該類的虛函數指針 { PTR ptr = NULL; //如今讓pi能訪問類的虛函數指針 int *pi = (int *)p; int i = 0; while (pi [i ]) { ptr = (PTR)pi[i]; ptr(); i++; } } int main () { //Base b; //Base2 b2; D d; //PrintVT(*(int *)&b); //cout << "--------------------" << endl; //PrintVT(*(int *)&b2); //cout << "--------------------" << endl; PrintVT(*( int *)&d ); cout << "--------------------" << endl ; getchar(); return 0; }
如上述代碼,咱們發現多繼承的虛函數表和單繼承由很大的不一樣之處
在此再也不贅述兩個基類的虛表,咱們來看派生類的對象模型
*咱們發如今派生類中有兩個虛函數表,而且派生類本身的虛函數被存入了第一個虛函數表
上述代碼運行的結果是
tips:
*在一個對象中繼承自基類的部分和派生類的自定義部分不必定是連續存儲的
*若是在基類裏定義了一個靜態成員那麼這個成員是惟必定義的,只存在一個實例
*含有關鍵字final的類不能夠做爲基類被繼承
*動態綁定基於給用基類的指針或者引用綁定對象。除了內置指針外智能指針也是能夠作到這樣的 類 型轉換的
C++的多態性:咱們把具備繼承關係的多個類型稱爲多態類型,由於咱們可使用這些類型的多種形式而無須在乎他們的差別
覆蓋:派生類從新定義了基類的虛函數而且他們的函數名,參數列表和返回值都必須相同可是協變的返 回值必須不一樣。
隱藏:派生類從新中定義了基類中同名的函數(非虛函數和靜態函數)此時基類中的同名函數被隱藏
重載:在同一個做用域內咱們定義了幾個同名函數他們經過參數列表來區分彼此稱爲重載
*咱們能夠在支持C++11的編譯器中給覆蓋加上override關鍵字,那麼咱們在編寫該函數時編譯器會檢查 它形式的正確性,保證咱們的調試變得更加簡單