class Person{PRivate: int _p;};class Student:public Person{private: int _s;};class Teacher:public Person{private: int _t;};class Assistant:public Student,public Teacher{private: int _a;};int main(){ printf("%d/n",sizeof(Assistant)); system("pause"); return 0;}輸出的結果為20(后面詳述菱形繼承)2.派生類的聲明方式 class 派生類名 : [繼承方式] 基類名 { 派生類新增加的成員; }; 繼承方式:public(公有繼承) protected(保護繼承) private(私有繼承) 當沒有給出繼承方式時,使用關鍵字class聲明派生類默認繼承方式是private,使用關鍵字struct時默認繼承方式是public.3.派生類的構成
構造一個派生類包含三部分工作:從基類接受成員;調整從基類接受的成員;(調整:指定繼承方式;聲明與基類相同名字的成員或函數,函數參數列表也要相同,構成隱藏,若參數列表不同,并不能認為它構成了重載,因為兩個函數并不在同一作用域中,不滿足重載的條件,具體是什么還不太了解,但類外不能調用該基類中的函數;)在聲明派生類是增加成員;4.派生類的成員訪問屬性
不同的繼承方式決定了基類成員在派生類中的訪問屬性公用繼承 基類的公有成員和保護成員在派生類中保持原有的訪問屬性,其私有成員被繼承,但任為基類私有(不可見) 公有成員:在基類、派生類和類外均可訪問私有繼承 基類的公有成員和保護成員在派生類變為私有成員,其私有成員被繼承,但任為基類私有(都不可見) 私有成員:基類的私有成員只能在基類內部訪問,派生類和類外均不可訪問保護繼承 基類的共有成員和保護成員在派生類中變成了保護成員,其私有成員被繼承,但任為基類私有(不可見) 保護成員:基類的私有成員可以在基類內部和派生類中訪問,類外不允許訪問公用繼承中,派生類直接訪問基類的私有成員是不允許的,只有通過基類的公有成員函數來引用基類的私有成員;私有繼承中,不能通過派生類的對象來訪問從私有基類繼承過來的任何成員或函數,但可以通過派生類的成員函數調用私有基類的公用成員函數來實現對基類私有成員的訪問。5.派生類的構造函數和析構函數
基類的構造函數和析構函數時不能被繼承的 構造函數一般形式: 派生類的構造函數名(總參數列表) :基類的構造函數名(參數列表) [,子類對象(參數列表)] { 派生類新增數據成員初始化語句 } 繼承關系中構造函數的調用順序 派生類的構造函數(按照繼承列表的順序)------>初始化列表中調用基類構造函數----->基類構造函數體----> 派生類的構造函數體繼承關系中析構函數的調用順序 派生類的構造函數---->派生類的構造函數體---->基類的析構函數--->基類的析構函數體(與構造函數相反)說明:基類沒有缺省的構造函數(即沒有缺省值和半缺省),派生類必須要在初始化列表中顯示的給出基類名和參數列表。(必須顯示的定義構造函數情景二) 必須顯示的定義構造函數情景一:存在兩個類,A和B,B類中定義了A類的對象,A類中定義了沒有缺省的構造 函數,則B類一定要顯示給出構造函數 基類沒有定義構造函數,則派生類也可以不用定義,全部使用缺省的構造函數(全缺省和系統默認合成的構造函數) 事例:class Test1{public: Test1(int data) { cout<<"Test1()"<<endl; } ~Test1() { cout<<"~Test1()"<<endl; }};class Test2{public: Test2(int data) { cout<<"Test2()"<<endl; } ~Test2() { cout<<"~Test2()"<<endl; }};class Base1{public: Base1(int data) :_data1(data) { cout<<"Base1()"<<endl; } ~Base1() { cout<<"~Base1()"<<endl; }protected: int _data1;};class Base2{public: Base2(int data) :_data2(data) { cout<<"Base2()"<<endl; } ~Base2() { cout<<"~Base2()"<<endl; }protected: int _data2;};class Derive:public Base1,public Base2{public: /*Derive() :Base1(0) ,Base2(1) ,t1(3) ,t2 (4)*/ //兩種情況結果相同 Derive() :t2(3) ,t1(4) //與對象的定義順序有關 ,Base1(0) ,Base2(1) //與繼承時的聲明順序有關 { cout<<"Deriver()"<<endl; } ~Derive() { cout<<"~Deriver()"<<endl; }protected: Test1 t1; Test2 t2;};void funtest(){ Derive d1;}int main(){ funtest(); system("pause"); return 0;}結果圖:靜態成員可以繼承
6.繼承與轉換-----賦值兼容規則----public規則
子類對象可以賦值給父類對象-----賦值的那部分是子類繼承父類的部分父類的對象不能賦值給子類的對象---->程序會崩潰(因為賦值給派生類對象的區域為未知區域,系統不允許)父類的指針、引用可以指向子類對象,(但不能訪問派生類新增加的部分,因為父類不能強制轉化為子類)子類的指針、引用不能指向父類的對象(可以通過強制類型轉換完成)是不是不太明白,我們可以用程序示例和畫圖來解釋class A{public: A(int data = 1) :_a(data) {}private: int _a;};class B:public A{public: B(int data1) :_b(data1) {}private: int _b;};int main(){ A a(1); //父類對象 B b(2); //子類對象 A* _a; //父類指針 B* _b; //子類指針 /*b = a; */ //父類給子類賦值,運行出錯 a = b; //子類給父類賦值,運行成功 _a = &b; //父類對象指向子類指針,運行成功 //_a->_b = 1; //訪問派生類對象出錯 //_b = &a; //子類指針指向父類對象,運行出錯,原因是無法將A*轉化為B* _b = (B*)&a; //將地址強制類型轉化為B類的地址,運行成功 return 0;}
新聞熱點
疑難解答
圖片精選