C++ 继承解析
?
繼承
?
1、概念:
繼承(inheritance)機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類(lèi)特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能。這樣產(chǎn)生新的類(lèi),稱(chēng)派生類(lèi)。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu),體現(xiàn)了由簡(jiǎn)單到復(fù)雜的認(rèn)知過(guò)程。
一個(gè)新類(lèi)從已有的類(lèi)中獲得其已有的特性稱(chēng)為繼承,被繼承的稱(chēng)為父類(lèi)(Base class)或基類(lèi),新產(chǎn)生的類(lèi)稱(chēng)為派生類(lèi)或子類(lèi)。
?
?
2、訪(fǎng)問(wèn)限定符與繼承關(guān)系
?
類(lèi)的成員有三種訪(fǎng)問(wèn)限定符:public(公有)、protected(保護(hù))、
private(私有)
?
繼承的方式:public(公有繼承)、protected(保護(hù)繼承)、
Private(私有繼承)
?
3、繼承的方式:
繼承權(quán)限規(guī)則表
| 繼承方式 | 基類(lèi)的public成員 | 基類(lèi)的protected成員 | 基類(lèi)的private成員 | 繼承引起的訪(fǎng)問(wèn)控制變化 |
| Public | Public | Protected | 不可見(jiàn) | 基類(lèi)成員在派生類(lèi)中訪(fǎng)問(wèn)權(quán)限不變 |
| Protected | Protected | Protected | 不可見(jiàn) | 基類(lèi)的非私有成員成為子類(lèi)的保護(hù)成員 |
| Private | Private | Private | 不可見(jiàn) | 基類(lèi)的所有成員成為子類(lèi)的私有成員 |
?
?
基類(lèi):
class Base
{
public:
????? Base()
?????????? :pub(1)
?????????? ,pro(2)
?????????? ,pri(3)
????? {}
?
public:
????? int pub;
?
protected:
????? int pro;
?
private:
????? int pri;
?
};
?
(1)公有繼承:采用公有繼承時(shí),基類(lèi)成員的訪(fǎng)問(wèn)權(quán)限在派生類(lèi)中不變
class Derived1:public Base
{
public:
?????? Derived1()
????????????? :d_pub(4)
????????????? ,d_pro(5)
????????????? ,d_pri(6)
?????? {}
?????? void SetData()
?????? {
????????????? pub = 0;
????????????? pro = 0;
????????????? pri = 0;?? //子類(lèi)無(wú)法訪(fǎng)問(wèn)基類(lèi)的私有成員
?????? }
?
public:
?????? int d_pub;
protected:
?????? int d_pro;
private:
?????? int d_pri;
};
?
void FunTest()
{
?????? Base b;
?????? b.pub = 1;
?????? b.pro = 2;???
?????? b.pri = 3;???? ?? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
?
?????? Derived1 d1;
?????? d1.pub = 1;
?????? d1.pro = 2;
?????? d1.pri = 3;?? //子類(lèi)對(duì)象無(wú)法訪(fǎng)問(wèn)基類(lèi)的保護(hù)、私有成員
?
?????? d1.d_pub = 4;
?????? d1.d_pro = 4;
?????? d1.d_pri = 4;???? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
}
?
(2)保護(hù)繼承:基類(lèi)的公有、保護(hù)成員成為派生類(lèi)的保護(hù)成員。
?
class Derived2:protected Base
{
public:
?????? Derived2()
????????????? :d_pub(4)
????????????? ,d_pro(5)
????????????? ,d_pri(6)
?????? {}
?????? void SetData()
?????? {
????????????? pub = 0;? //成為子類(lèi)的保護(hù)成員
????????????? pro = 0;
????????????? pri = 0;?? //子類(lèi)無(wú)法訪(fǎng)問(wèn)基類(lèi)的私有成員
?????? }
?
public:
?????? int d_pub;
protected:
?????? int d_pro;
private:
?????? int d_pri;
};
?
void FunTest()
{
?????? Base b;
?????? b.pub = 1;
?????? b.pro = 2;???
?????? b.pri = 3;???? ?? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
?
?????? Derived2 d2;
?????? d2.pub = 1; ? //成為子類(lèi)的保護(hù)成員,無(wú)法訪(fǎng)問(wèn)
?????? d2.pro = 2;
?????? d2.pri = 3;? //子類(lèi)對(duì)象無(wú)法訪(fǎng)問(wèn)基類(lèi)的保護(hù)、私有成員
?
?????? d2.d_pub = 4;
?????? d2.d_pro = 4;
?????? d2.d_pri = 4;???? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
}
(3)私有繼承
class Derived3:private Base
{
public:
?????? Derived3()
????????????? :d_pub(4)
????????????? ,d_pro(5)
????????????? ,d_pri(6)
?????? {}
?????? void SetData()
?????? {
????????????? pub = 0;? //成為子類(lèi)的私有成員
????????????? pro = 0;
????????????? pri = 0;?? //子類(lèi)無(wú)法訪(fǎng)問(wèn)基類(lèi)的私有成員
?????? }
?
public:
?????? int d_pub;
protected:
?????? int d_pro;
private:
?????? int d_pri;
};
?
void FunTest()
{
?????? Base b;
?????? b.pub = 1;
?????? b.pro = 2;???
?????? b.pri = 3;???? ?? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
?
?????? Derived3 d3;
?????? d3.pub = 1; ? //成為子類(lèi)的私有成員,無(wú)法訪(fǎng)問(wèn)
?????? d3.pro = 2;
?????? d3.pri = 3;?? //子類(lèi)對(duì)象無(wú)法訪(fǎng)問(wèn)基類(lèi)的保護(hù)、私有成員
?
?????? d3.d_pub = 4;
?????? d3.d_pro = 4;
?????? d3.d_pri = 4;???? //類(lèi)外無(wú)法訪(fǎng)問(wèn)類(lèi)的保護(hù)、私有成員
}
?
?
?
2、?總結(jié):
?
(1)??????類(lèi)的保護(hù)成員和私有成員在類(lèi)外部都不可訪(fǎng)問(wèn),基類(lèi)的私有成員在派生類(lèi)都不可訪(fǎng)問(wèn)。
?
?
(2)???public繼承是一個(gè)接口繼承,保持is-a原則,每個(gè)父類(lèi)可用的成員對(duì)子類(lèi)也可用,因?yàn)槊總€(gè)子類(lèi)對(duì)象也都是一個(gè)父類(lèi)對(duì)象。
?
例如:有一個(gè)Horse類(lèi)可以保存關(guān)于馬的所有信息,身高體重等等,那么我們就可以從Horse類(lèi)中派生出白馬類(lèi),白馬類(lèi)包含所有Horse類(lèi)的成員,在白馬類(lèi)中可以新增關(guān)于白馬的成員,這個(gè)成員通常不用于Horse類(lèi)。
?????????? class Horse
{
public:
??? int Tall;
??? int Weight;
};
classWhiteHorse:public Horse
{
public:
??? int Color;
};
WhiteHorse是Horse的一個(gè)子類(lèi),包括了Horse類(lèi)的所有成員,is_a是一種關(guān)系
?
?
(3)???protetced/private繼承是一個(gè)實(shí)現(xiàn)繼承,基類(lèi)的部分成員并非完全成為子類(lèi)接口的一部分,是 has-a 的關(guān)系原則,所以非特殊情況下不會(huì)使用這兩種繼承關(guān)系,在絕大多數(shù)的場(chǎng)景下使用的都是公有繼承。
?
實(shí)現(xiàn)繼承的主要目標(biāo)是代碼重用,我們發(fā)現(xiàn)類(lèi)B和類(lèi)C存在同樣的代碼,因此我們?cè)O(shè)計(jì)了一個(gè)類(lèi) A,用于存放通用的代碼,基于這種思路的繼承稱(chēng)為實(shí)現(xiàn)繼承。?
基類(lèi)的成員在派生類(lèi)中是私有的,基類(lèi)方法將不會(huì)成為派生對(duì)象公有接口的一部分,但可以在派生類(lèi)的成員函數(shù)中使用它們,基類(lèi)方法將不會(huì)成為派生對(duì)象公有接口的一部分,但可以在派生類(lèi)的成員函數(shù)中使用它們。
?
?class Banana
{..};
class Lauch
{
private:
classBanana; ......
};
?
(4)???基類(lèi)的 private 成員在派生類(lèi)中是不能被訪(fǎng)問(wèn)的,如果基類(lèi)成員不想在類(lèi)外直接被訪(fǎng)問(wèn),但需要在派生類(lèi)中能訪(fǎng)問(wèn),就定義為 protected 。可以看出保護(hù)成員限定符是因繼承才出現(xiàn)的。
?
(5)???使用關(guān)鍵字class時(shí)默認(rèn)的繼承方式是private,使用struct時(shí)默認(rèn)的繼承方式是public,不過(guò)最好顯示的寫(xiě)出繼承方式。
?
3、?派生類(lèi)的默認(rèn)成員函數(shù)
在繼承關(guān)系里面,在派生類(lèi)中如果沒(méi)有顯示定義這六個(gè)成員函數(shù),編譯系統(tǒng)則會(huì)默認(rèn)合成這六個(gè)默認(rèn)
的成員函數(shù)。
?
(1)???構(gòu)造函數(shù)調(diào)用順序:
進(jìn)入子類(lèi)的構(gòu)造函數(shù)——>調(diào)用基類(lèi)構(gòu)造函數(shù)——>執(zhí)行子類(lèi)構(gòu)造函數(shù)
說(shuō)明:
1)、基類(lèi)沒(méi)有缺省構(gòu)造函數(shù),派生類(lèi)必須要在初始化列表中顯式給出基類(lèi)名和參數(shù)列表。
2)、基類(lèi)沒(méi)有定義構(gòu)造函數(shù),則派生類(lèi)也可以不用定義,全部使用缺省構(gòu)造函數(shù)。
3)、基類(lèi)定義了帶有形參表構(gòu)造函數(shù),派生類(lèi)就一定定義構(gòu)造函數(shù)
?
(2)??????析構(gòu)函數(shù)調(diào)用順序:
派生類(lèi)析構(gòu)函數(shù)——>派生類(lèi)包含成員對(duì)象的析構(gòu)函數(shù)——>基類(lèi)析構(gòu)函數(shù)
class Base
{
public:
?????? Base()
?????? {
????????????? ?cout<<"Base()"<<endl;
?????? }
?????? Base(int b, int r, int i)
????????????? :pub(1)
????????????? ,pro(2)
????????????? ,pri(3)
?????? {
????????????? cout<<"Base(int , int , int)"<<endl;
?????? }
?????? ~Base()
?????? {
????????????? cout<<"~Base()"<<endl;
?????? }
public:
?????? int pub;
protected:
?????? int pro;
private:
?????? int pri;
};
class Derived3:public Base
{
public:
?????? Derived3()
?????? {
????????????? ??cout<<"Derived3()"<<endl;
?????? }
?????? Derived3(int d1, int d2, int d3)
????????????? :Base(d1, d2, d3)
?????? {
????????????? d_pub = d1;
????????????? cout<<"Derived3()???----"<<"d_pub="<<d_pub<<endl;
?????? }
?????? ~ Derived3()
?????? {
????????????? cout<<"~Derived3()"<<endl;
?????? }
public:
?????? int d_pub;
protected:
?????? int d_pro;
private:
?????? int d_pri;
};
void FunTest()
{
?????? Derived3 d0;
?????? Derived3 d3(1, 2, 3);
}
?
?
?
4、即成體系中的作用域:
(1)在繼承體系中基類(lèi)和派生類(lèi)是兩個(gè)不同作用域。
(2) 子類(lèi)和父類(lèi)中有同名成員,子類(lèi)成員將屏蔽父類(lèi)對(duì)成員的直接訪(fǎng)問(wèn)。(在子類(lèi)成員函數(shù)中,可以使用 基類(lèi)::基類(lèi)成員 訪(fǎng)問(wèn))--隱藏 --重定義
(3) 注意在實(shí)際中在繼承體系里面最好不要定義同名的成員
?
5、繼承與轉(zhuǎn)換--賦值兼容規(guī)則:(public繼承)
(1)子類(lèi)對(duì)象可以賦值給父類(lèi)對(duì)象(切割/切片)
(2)父類(lèi)對(duì)象不能賦值給子類(lèi)對(duì)象
(3)父類(lèi)的指針/引用可以指向子類(lèi)對(duì)象
(4)子類(lèi)的指針/引用不能指向父類(lèi)對(duì)象(可以通過(guò)強(qiáng)制類(lèi)型轉(zhuǎn)換完成)
class Base
{
public:
?????? Base()
?????? {
????????????? ?cout<<"Base()"<<endl;
?????? }
?????? Base(int b, int r, int i)
????????????? :pub(1)
????????????? ,pro(2)
????????????? ,pri(3)
?????? { cout<<"Base(int , int , int)"<<endl; }
?????? ~Base()
?????? {cout<<"~Base()"<<endl;}
?
public:
?????? int pub;
?
protected:
?????? int pro;
?
private:
?????? int pri;
};
class Derived:public Base
{
public:
?????? Derived()
?????? { cout<<"Derived3()"<<endl; }
?????? Derived(int d1, int d2, int d3)
????????????? :Base(d1, d2, d3)
?????? {
????????????? d_pub = d1;
????????????? cout<<"Derived()"<<endl;
?????? }
?????? ~ Derived()
?????? { cout<<"~Derived()"<<endl; }
public:
?????? int d_pub;
protected:
?????? int d_pro;
private:
?????? int d_pri;
};
?
void FunTest()
{
?????? Base b0;
?????? Base b1(1, 2, 3);
?????? Base* pBase;
??????
?
?????? Derived d0;
?????? Derived d1(4, 5, 6);
?????? ?Derived* pDerived;
?
?????? b0 = d0;?//子類(lèi)對(duì)象可以賦值給父類(lèi)對(duì)象
?????? b1 = d1;
?
?????? d0 = bo; //? 父類(lèi)對(duì)象不能賦值給子類(lèi)對(duì)象
?????? d1 = b1;
?
?????? pBase = &d0;???? //父類(lèi)的指針/引用可以指向子類(lèi)對(duì)象
?????? pBase = &d1;
?
?????? Base& _b0 = d0;
?????? Base& _b1 = d1; //父類(lèi)的指針/引用可以指向子類(lèi)對(duì)象
?
?????? pDerived = &b0;
?????? Derived& = b1;//子類(lèi)的指針/引用不能指向父類(lèi)對(duì)象
?
?????? pDerived = (Derived *)&b1;?????? //可以使用的強(qiáng)制類(lèi)型轉(zhuǎn)換使子類(lèi)的指針/引用指向父類(lèi)對(duì)象
?
}
?
6、友元與繼承
友元關(guān)系不能繼承,也就是說(shuō)基類(lèi)友元不能訪(fǎng)問(wèn)子類(lèi)私有和保護(hù)成員。
class Base
{
public:
?????? Base()
?????? {
????????????? pub = 10;
????????????? pro = 10;
????????????? pri = 10;
????????????? ?cout<<"Base()"<<endl;
?????? }
?????? ~Base()
?????? {
????????????? cout<<"~Base()"<<endl;
?????? }
public:
?????? int pub;
protected:
?????? int pro;
private:
?????? int pri;
?friend void?????? show();
};
class Derived:public Base
{
public:
?????? Derived()
?????? {
????????????? d_pri= 10 ;
????????????? cout<<"Derived3()"<<endl;
?????? }
private:
?????? int d_pri;
};
void?????? show()
{
?????? Base b;
?????? cout<<b.pri<<endl; //友元函數(shù)可以訪(fǎng)問(wèn)基類(lèi)的私有成員
?????? Derived d;
?????? cout<<d.d_pri<<endl;?? //友元函數(shù)不能繼承,基類(lèi)的友元函數(shù)不可以訪(fǎng)問(wèn)子類(lèi)的私有成員
}
?
7、繼承的類(lèi)型
(1)單繼承:
class A
{
public:
?????? int data1;
} ;
class B? :public A
{
public:
?????? int data2;
} ;
(2)多繼承:
class A
{
public:
?????? int data1;
} ;
class B?
{
public:
?????? int data2;
}? ;
?class C :public A ,public B
{
public:
?????? int data3;
} ;
?
?
(3)???菱形繼承:
??????? class A
{
public:
?????? int data1;
} ;
class B: public A??????
{
public:
?????? int data2;
}? ;
?class C:public A
{
public:
?????? int data3;
} ;
class D:public B,public C
{
public:
?????? int data4;
} ;
?
?
?
?
?
D類(lèi)的對(duì)象中存在兩份A對(duì)象成員,菱形繼承存在二義性和數(shù)據(jù)冗余問(wèn)題
?
?
8、虛繼承--解決菱形繼承的二義性和數(shù)據(jù)冗余的問(wèn)題
?
?
?
class A
{
public:
??? int data1;
?
} ;
?
class B: virtual public A??
{
public:
??? int data2;
}? ;
?class C: virtual public A
{
public:
??? int data3;
} ;
?
?class D:public B,public C
{
public:
??? int data4;
} ;
?
?void FunTest()
?{
??? ?D d;
??? ?d.data1 = 1;
??? ?d.data2 = 2;
??? ?d.data3?= 3;
??? ?d.data4?= 4;
??? ?cout<<sizeof(B)<<endl;//12
??? ?cout<<sizeof(D)<<endl;//24
//0x0098F73C?000ecc88 00000002 000ecc94 00000003 00000004 00000001 ??? ?
?
?}
?
(1)虛繼承解決了在菱形繼承體系里面子類(lèi)對(duì)象包含多份父類(lèi)對(duì)象的數(shù)據(jù)冗余&浪費(fèi)空間的問(wèn)題。
(2)虛繼承體系看起來(lái)好復(fù)雜,在實(shí)際應(yīng)用我們通常不會(huì)定義如此復(fù)雜的繼承體系。一般不到萬(wàn)不得已都不要定義菱形結(jié)構(gòu)的虛繼承體系結(jié)構(gòu),
因?yàn)槭褂锰摾^承解決數(shù)據(jù)冗余問(wèn)題也帶來(lái)了性能上的損耗。
?就寫(xiě)到這了,有什么不對(duì)的大家指正哈!!!
?
?
?
總結(jié)
- 上一篇: python Socket 客户端
- 下一篇: s3c2440移植MQTT