十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
目錄

一.繼承的認(rèn)識(shí)
1.1繼承的概念
1.2繼承的定義
1.2.1 繼承關(guān)系與訪問(wèn)限定符
1.2.2 繼承基類成員訪問(wèn)方式
二.基類與派生類對(duì)象的相互賦值轉(zhuǎn)換
三.繼承中的作用域
四.派生類的默認(rèn)成員函數(shù)
五.繼承與友元
?編輯六.繼承與靜態(tài)成員?
七.菱形繼承
八.繼承與組合
總結(jié):
1.2繼承的定義繼承(inheritance)機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能,這樣產(chǎn)生新的類,稱派生類。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu), 體現(xiàn)了由簡(jiǎn)單到復(fù)雜的認(rèn)知過(guò)程。
我們定義了一個(gè)Student的派生類,也被稱為子類。Person是基類,也被稱為父類。



比較常用的四種繼承方式:?
1.基類的類成員繼承方式是public,派生類的繼承方式是public繼承;
2.基類的類成員繼承方式是public,派生類的繼承方式是protected繼承;
3.基類的類成員繼承方式是protected,派生類的繼承方式是public繼承;
4.基類的類成員繼承方式是protected,派生類的繼承方式是protected繼承;

首先先來(lái)理解不可見(jiàn),不可見(jiàn)的意思是在父類中的私有成員變量還是被集成到子類中,但是因?yàn)檎Z(yǔ)法的限制,父類的私有成員無(wú)論是在子類對(duì)象的外部還是內(nèi)部都是不可以進(jìn)行訪問(wèn)的.

理解一下protected繼承,因?yàn)閜rotetced/private繼承下來(lái)的成員都只能在派生類的類里面使用,實(shí)際中擴(kuò)展維護(hù)性不強(qiáng);
1.在派生類中進(jìn)行使用:



在派生類中,可以對(duì)protected的對(duì)象進(jìn)行改變,也可以打印出對(duì)應(yīng)的結(jié)果類型.

但是如果不是在派生類中對(duì)父類的protected對(duì)象進(jìn)行改變的話,在主函數(shù)中進(jìn)行改變,會(huì)提示不可訪問(wèn)!

最后總結(jié)一下:他們?nèi)N繼承的相互關(guān)系:public >protected >private.
保護(hù)和私有在父類中沒(méi)有區(qū)別;在子類中,private成員不可見(jiàn),protected成員是可見(jiàn)的
二.基類與派生類對(duì)象的相互賦值轉(zhuǎn)換對(duì)于常見(jiàn)繼承的使用,我有以下的總結(jié):
1.子類繼承父類的方式是public,public繼承基本沒(méi)有受到什么限制,子類中的public成員,可以在函數(shù)外面進(jìn)行使用賦值;子類中的protected成員以及public繼承過(guò)來(lái)的父類的protected成員都是不能夠在子類外面進(jìn)行改變的,但是可以在子類內(nèi)部進(jìn)行改變賦值.父類中的private成員在子類中是不可見(jiàn)的,顯然也是不可以進(jìn)行修改的.
2.子類繼承父類的方式是protected,這個(gè)繼承是會(huì)降級(jí)處理的,基本上除了父類的private成員變量不可以進(jìn)行修改之外,其他類型的成員變量均可以在子類中進(jìn)行賦值改變,當(dāng)然在子類外不可以進(jìn)行改變
3.子類繼承父類的方式是private,基本都會(huì)受限.
注意:
class默認(rèn)訪問(wèn)限定符是private;struct 默認(rèn)訪問(wèn)限定符是public
class繼承中默認(rèn)繼承方式是priavte繼承;struct繼承默認(rèn)public繼承
派生類(子類)對(duì)象可以賦值給基類(父類)對(duì)象/指針/引用;
即將父類中那部分賦值給基類;
這里有個(gè)形象的說(shuō)法叫切片或者切 割。寓意把派生類中父類那部分切來(lái)賦值過(guò)去;
基類對(duì)象不能賦值給派生類對(duì)象


1.子類對(duì)象可以賦值給父類對(duì)象/指針/引用

2.基類對(duì)象不能賦值給派生類對(duì)象

3.基類的指針可以通過(guò)強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針


這個(gè)其實(shí)還有個(gè)特殊情況,取基類的地址強(qiáng)制轉(zhuǎn)換成子類的指針,進(jìn)而強(qiáng)制給子類進(jìn)行賦值,但是這種情況可能會(huì)導(dǎo)致越界訪問(wèn)這種情況.

1. 在繼承體系中基類和派生類都有獨(dú)立的作用域。
2. 子類和父類中有同名成員,子類成員將屏蔽父類對(duì)同名成員的直接訪問(wèn),這種情況叫隱藏,也叫重定義.(在子類成員函數(shù)中,可以使用 基類::基類成員顯式訪問(wèn))
3. 需要注意的是如果是成員函數(shù)的隱藏,只需要函數(shù)名相同就構(gòu)成隱藏。
4. 注意在實(shí)際中在繼承體系里面最好不要定義同名的成員。
// Student的_num和Person的_num構(gòu)成隱藏關(guān)系,可以看出這樣代碼雖然能跑,但是非常容易混淆
class Person
{
protected :
string _name = "小李子"; // 姓名
int _num = 111; // 身份證號(hào)
};
class Student : public Person
{
public:
void Print()
{
cout<<" 姓名:"<<_name<< endl;
cout<<" 身份證號(hào):"<運(yùn)行結(jié)果如下:

從運(yùn)行結(jié)果上面可以看出,子類和父類中有同名成員,子類成員將屏蔽父類對(duì)同名成員的直接訪問(wèn),直接訪問(wèn)子類的成員變量.
// B中的fun和A中的fun不是構(gòu)成重載,因?yàn)椴皇窃谕蛔饔糜?// B中的fun和A中的fun構(gòu)成隱藏,成員函數(shù)滿足函數(shù)名相同就構(gòu)成隱藏。
class A
{
public:
void fun()
{
cout<< "func()"<< endl;
}
};
class B : public A
{
public:
void fun(int i)
{
//加上限制性訪問(wèn)符
//直接訪問(wèn)A類中的成員函數(shù)fun()
A::fun();
cout<< "func(int i)->"<運(yùn)行結(jié)果如下:

6個(gè)默認(rèn)成員函數(shù),“默認(rèn)”的意思就是指我們不寫,編譯器會(huì)變我們自動(dòng)生成一個(gè),那么在派生類中,這幾個(gè)成員函數(shù)是如何生成的呢?
1. 派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)初始化基類的那一部分成員。如果基類沒(méi)有默認(rèn)的構(gòu)造函數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。
2. 派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
3. 派生類的operator=必須要調(diào)用基類的operator=完成基類的復(fù)制。
4. 派生類的析構(gòu)函數(shù)會(huì)在被調(diào)用完成后自動(dòng)調(diào)用基類的析構(gòu)函數(shù)清理基類成員。因?yàn)檫@樣才能保證派生類 對(duì)象先清理派生類成員再清理基類成員的順序。
5. 派生類對(duì)象初始化先調(diào)用基類構(gòu)造再調(diào)派生類構(gòu)造。
6. 派生類對(duì)象析構(gòu)清理先調(diào)用派生類析構(gòu)再調(diào)基類的析構(gòu)。


友元關(guān)系不能繼承,也就是說(shuō)基類友元不能訪問(wèn)子類私有和保護(hù)成員;

友元關(guān)系不能繼承,這樣的就進(jìn)行報(bào)錯(cuò)了,如果想去掉這個(gè)報(bào)錯(cuò)信息,將友元關(guān)系添加到子類成員中就可以.
六.繼承與靜態(tài)成員?基類定義了static靜態(tài)成員,則整個(gè)繼承體系里面只有一個(gè)這樣的成員;
class Person
{
public :
Person () {++ _count ;}
protected :
string _name ; // 姓名
public :
static int _count; // 統(tǒng)計(jì)人的個(gè)數(shù)。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
int _stuNum ; // 學(xué)號(hào)
};
class Graduate : public Student
{
protected :
string _seminarCourse ; // 研究科目
};
void TestPerson()
{
Student s1 ;
Student s2 ;
Student s3 ;
Graduate s4 ;
cout<<" 人數(shù) :"<< Person ::_count<< endl;
Student ::_count = 0;
cout<<" 人數(shù) :"<< Person ::_count<< endl;
}在程序上面進(jìn)行運(yùn)行如下:

創(chuàng)建構(gòu)造了4個(gè)父類Person 對(duì)象,因?yàn)開(kāi)count是靜態(tài)變量,不進(jìn)行銷毀,所以第一次輸出的人數(shù)是4.
第二次輸出人數(shù)時(shí),Student類中對(duì)_count進(jìn)行置零,輸出"人數(shù):0".
七.菱形繼承單繼承:一個(gè)子類只有一個(gè)直接父類時(shí)稱這個(gè)繼承關(guān)系為單繼承
?
多繼承:一個(gè)子類有兩個(gè)或以上直接父類時(shí)稱這個(gè)繼承關(guān)系為多繼承?
?
菱形繼承:菱形繼承是多繼承的一種特殊情況。

菱形繼承的問(wèn)題:從下面的對(duì)象成員模型構(gòu)造,可以看出菱形繼承有數(shù)據(jù)冗余和二義性的問(wèn)題。在Assistant的對(duì)象中Person成員會(huì)有兩份。

虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問(wèn)題,在Student和Teacher的繼承;
加關(guān)鍵字:virtual
菱形繼承的內(nèi)存對(duì)象成員模型:可以在監(jiān)視窗口上面看到內(nèi)存上面的數(shù)據(jù)冗余.


d中的繼承父類B和C中都繼承了A類,均對(duì)于A類中的成員變量_a進(jìn)行了賦值,且都放在了不同的地址空間上面.
菱形虛擬繼承的內(nèi)存對(duì)象成員模型:這里可以分析出D對(duì)象中將A放到的了對(duì)象組成的最下面,這個(gè)A同時(shí)屬于B和C,那么B和C如何去找到公共的A呢?
這里是通過(guò)了B和C的兩個(gè)指針,指向的一張表。這兩個(gè)指針叫虛基表指針,這兩個(gè)表叫虛基表。虛基表中存的偏移量。通過(guò)偏移量可以找到下面的A。
虛基表:存放偏移量

public繼承是一種is-a的關(guān)系。也就是說(shuō)每個(gè)派生類對(duì)象都是一個(gè)基類對(duì)象。
組合是一種has-a的關(guān)系。假設(shè)B組合了A,每個(gè)B對(duì)象中都有一個(gè)A對(duì)象。
優(yōu)先使用對(duì)象組合,而不是類繼承 。
繼承允許你根據(jù)基類的實(shí)現(xiàn)來(lái)定義派生類的實(shí)現(xiàn)。這種通過(guò)生成派生類的復(fù)用通常被稱為白箱復(fù)用 (white-box reuse)。術(shù)語(yǔ)“白箱”是相對(duì)可視性而言:在繼承方式中,基類的內(nèi)部細(xì)節(jié)對(duì)子類可見(jiàn) .?繼承一定程度破壞了基類的封裝,基類的改變,對(duì)派生類有很大的影響。派生類和基類間的依賴關(guān) 系很強(qiáng),耦合度高。
對(duì)象組合是類繼承之外的另一種復(fù)用選擇。新的更復(fù)雜的功能可以通過(guò)組裝或組合對(duì)象來(lái)獲得。對(duì) 象組合要求被組合的對(duì)象具有良好定義的接口。這種復(fù)用風(fēng)格被稱為黑箱復(fù)用(black-box reuse),?因?yàn)閷?duì)象的內(nèi)部細(xì)節(jié)是不可見(jiàn)的。對(duì)象只以“黑箱”的形式出現(xiàn)。 組合類之間沒(méi)有很強(qiáng)的依賴關(guān)系, 耦合度低。優(yōu)先使用對(duì)象組合有助于你保持每個(gè)類被封裝。
實(shí)際盡量多去用組合。組合的耦合度低,代碼維護(hù)性好。不過(guò)繼承也有用武之地的,有些關(guān)系就適合繼承那就用繼承,另外要實(shí)現(xiàn)多態(tài),也必須要繼承。類之間的關(guān)系可以用繼承,可以用組合,就用組合.
// Car和BMW Car和Benz構(gòu)成is-a的關(guān)系
class Car{
protected:
string _colour = "白色"; // 顏色
string _num = "京ABIT00"; // 車牌號(hào)
};
};
class BMW : public Car{
public:
void Drive() {cout<< "好開(kāi)-操控"<< endl;}
};
class Benz : public Car{
public:
void Drive() {cout<< "好坐-舒適"<< endl;}
};
// Tire和Car構(gòu)成has-a的關(guān)系
class Tire{
protected:
string _brand = "Michelin"; // 品牌
size_t _size = 17; // 尺寸
};
class Car{
protected:
string _colour = "白色"; // 顏色
string _num = "陜ABIT00"; // 車牌號(hào)
Tire _t; // 輪胎
};總結(jié):繼承屬于C++學(xué)習(xí)的一個(gè)難關(guān),限于筆者能力有限,如有錯(cuò)誤,請(qǐng)讀者進(jìn)行指正!謝謝大家!
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧