C++深入探究繼承的概念與使用
1、概念及定義
1.1 概念
繼承主要的工作就是-----共性抽取
具體地講:
①繼承機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要的手段;
②允許程序員在保持原有類(lèi)特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能。這樣實(shí)現(xiàn)的類(lèi)稱(chēng)為派生類(lèi)/子類(lèi)?;趯?shí)現(xiàn)該類(lèi)的原有類(lèi)稱(chēng)為基類(lèi)/父類(lèi)
③繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu),體現(xiàn)了由簡(jiǎn)單到復(fù)雜的認(rèn)知過(guò)程。(比如:animal—>dog---->kinds of dogs)
④繼承是類(lèi)層次設(shè)計(jì)的復(fù)用
1.2 定義
定義方式:class 派生類(lèi):繼承方式 基類(lèi)
繼承方式可以是 public、protected、private三種,他們?cè)诶^承基類(lèi)時(shí),所具有特性以及表現(xiàn)出的結(jié)果也有所不同,具體如下:
以public的方式繼承基類(lèi)

結(jié)論:
在public的繼承方式下:
①父類(lèi)中的成員變量的訪問(wèn)權(quán)限,到子類(lèi)中不會(huì)發(fā)生改變
②父類(lèi)中的私有訪問(wèn)權(quán)限的變量在子類(lèi)中不可見(jiàn)(不能直接被訪問(wèn))
問(wèn)題:類(lèi)在設(shè)計(jì)的時(shí)候,訪問(wèn)權(quán)限應(yīng)該如何選擇?
應(yīng)該遵循以下3點(diǎn)原則:

以protected的方式繼承基類(lèi)

結(jié)論:
在protected的繼承方式下:
①基類(lèi)中public修飾的 成員在子類(lèi)中訪問(wèn)權(quán)限為protected
②基類(lèi)中protected修飾的成員在子類(lèi)中的訪問(wèn)權(quán)限依舊是protected
③父類(lèi)中的private訪問(wèn)權(quán)限的變量在子類(lèi)中不可見(jiàn)(不能直接被訪問(wèn))
以private的方式繼承基類(lèi)

結(jié)論:
在private的繼承方式下:
①基類(lèi)中public修飾的 成員在子類(lèi)中訪問(wèn)權(quán)限為private
②基類(lèi)中protected修飾的成員在子類(lèi)中的訪問(wèn)權(quán)限為private
③父類(lèi)中的private訪問(wèn)權(quán)限的變量在子類(lèi)中不可見(jiàn)(不能直接被訪問(wèn))
上面詳細(xì)分析了每一種個(gè)情況,下面我們針對(duì)上面的結(jié)論進(jìn)行匯總:

注意:
1、基類(lèi)private成員在派生類(lèi)中無(wú)論以什么方式繼承都是不可見(jiàn)的。這里的不可見(jiàn)是指基類(lèi)的私有成員還是被繼承到了派生類(lèi)對(duì)象中,但是語(yǔ)法上限制派生類(lèi)對(duì)象不管在類(lèi)里面還是類(lèi)外面都不能去訪問(wèn)它。
2、基類(lèi)private成員在派生類(lèi)中是不能被訪問(wèn),如果基類(lèi)成員不想在類(lèi)外直接被訪問(wèn),但需要在派生類(lèi)中能訪問(wèn),就定義為protected??梢钥闯霰Wo(hù)成員限定符是因繼承才出現(xiàn)的
3、在實(shí)際運(yùn)用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因?yàn)閜rotetced/private繼承下來(lái)的成員都只能在派生類(lèi)的類(lèi)里面使用,實(shí)際中擴(kuò)展維護(hù)性不強(qiáng)。
2、class與struct的區(qū)別
主要有以下3點(diǎn)區(qū)別:

3、賦值兼容規(guī)則
前提:一定在public的繼承方式下才滿(mǎn)足
可以直接使用子類(lèi)對(duì)象給父類(lèi)對(duì)象賦值,反過(guò)來(lái)不行
這個(gè)很好理解,具體和可以通過(guò)兩個(gè)方面理解:
①子類(lèi)和父類(lèi)的關(guān)系是is–a的關(guān)系,因此使用子類(lèi)給父類(lèi)賦值時(shí)可以的
②從對(duì)象模型來(lái)說(shuō)。
對(duì)象模型可以簡(jiǎn)單理解為成員變量在內(nèi)存中的布局情況;

可以使用基類(lèi)的指針指向子類(lèi)的對(duì)象,反過(guò)來(lái)不行
如果一定要指向,必須強(qiáng)轉(zhuǎn),不推薦,僅僅是能通過(guò)編譯,但是在使用的時(shí)候可能會(huì)造成程序崩潰
分析如下:

可以使用基類(lèi)的引用去引用子類(lèi)對(duì)象,反過(guò)來(lái)不行
引用在底層本質(zhì)上就是使用指針實(shí)現(xiàn)的,因此它和指針的理解思路是一致的,這里就不再贅述。
4、繼承中的作用域問(wèn)題
明確:派生類(lèi)和基類(lèi)隸屬于不同的作用域
那么,現(xiàn)在有這樣一種情況:
基類(lèi)和派生類(lèi)中出現(xiàn)了同名的成員變量或成員方法。這種情況要如何去理解呢? 首先,他一定不是函數(shù)重載,因?yàn)楹瘮?shù)重載的前提必須是在同一作用域。 其實(shí)它就是我們本模塊要介紹的----同名隱藏(重定義)問(wèn)題
基類(lèi)和派生類(lèi)中出現(xiàn)同名的成員時(shí),會(huì)有如下問(wèn)題的存在:

那么,該如何解決呢?
只需要在訪問(wèn)的時(shí)候加上 基類(lèi)名稱(chēng)和作用域限定符即可,這樣做的目的是明確告訴編譯器被調(diào)用成員所處的作用域

建議:一般情況下,在繼承體系中最好不要定義同名的成員
5、派生類(lèi)(子類(lèi))的默認(rèn)成員函數(shù)
5.1 構(gòu)造函數(shù)
主要取決于基類(lèi)的情況,分為兩大類(lèi)進(jìn)行討論:
基類(lèi)沒(méi)有顯式定義任何構(gòu)造函數(shù)
子類(lèi)可以提供構(gòu)造函數(shù),也可以不提供構(gòu)造函數(shù) 是否提供根據(jù)子類(lèi)中完成的功能或者具體情況決定
基類(lèi)顯式定義了構(gòu)造函數(shù)
①基類(lèi)的構(gòu)造函數(shù)是無(wú)參或者全缺省的
子類(lèi)可以提供構(gòu)造函數(shù),也可以不提供構(gòu)造函數(shù)
是否提供根據(jù)子類(lèi)中完成的功能或者具體情況決定
②基類(lèi)的構(gòu)造函數(shù)是非默認(rèn)構(gòu)造函數(shù)
子類(lèi)必須要定義自己的構(gòu)造函數(shù)
在子類(lèi)構(gòu)造函數(shù)初始化列表位置顯式調(diào)用基類(lèi)的構(gòu)造函數(shù)(完成從基類(lèi)中繼承下來(lái)的成員的初始化工作)

基類(lèi)和子類(lèi)構(gòu)造函數(shù)的調(diào)用先后順序是怎樣的?
把握一點(diǎn):
創(chuàng)建那個(gè)類(lèi)的對(duì)象,編譯器就會(huì)調(diào)用這個(gè)類(lèi)的構(gòu)造函數(shù)
例如:創(chuàng)建子類(lèi)對(duì)象,本質(zhì)上調(diào)用的是子類(lèi)的構(gòu)造函數(shù),但是在子類(lèi)的構(gòu)造函數(shù)的初始化列表處會(huì)調(diào)用基類(lèi)的構(gòu)造方法來(lái)初始化從基類(lèi)繼承下來(lái)的對(duì)象。然后再去執(zhí)行子類(lèi)構(gòu)造函數(shù)的函數(shù)體。 因此,從結(jié)果上來(lái)看是基類(lèi)對(duì)象的構(gòu)造函數(shù)先執(zhí)行完畢,子類(lèi)構(gòu)造函數(shù)后執(zhí)行完畢。
5.2 拷貝構(gòu)造函數(shù)
取決于基類(lèi)的情況,主要分為兩類(lèi):
基類(lèi)的拷貝構(gòu)造函數(shù)未定義
子類(lèi)的拷貝構(gòu)造函數(shù)可定義可不定義,根據(jù)子類(lèi)的實(shí)際情況決定
基類(lèi)的拷貝構(gòu)造函數(shù)定義了
子類(lèi)也需要定義拷貝構(gòu)造函數(shù),并且需要在子類(lèi)的拷貝構(gòu)造函數(shù)初始化列表的位置顯式調(diào)用基類(lèi)的拷貝構(gòu)造函數(shù)

5.3 賦值運(yùn)算符重載
1.基類(lèi)的賦值運(yùn)算符重載未定義
子類(lèi)可定義可不定義
2.基類(lèi)的賦值運(yùn)算符重載顯式定義了
子類(lèi)也需要定義,分為兩個(gè)大的步驟:
①調(diào)用基類(lèi)的賦值運(yùn)算符重載給基類(lèi)部分成員賦值base::operator= (d);
②給子類(lèi)自己新增的部分進(jìn)行賦值
注意:基類(lèi)的operator= 與子類(lèi)自己的 operator= 構(gòu)成了同名隱藏,因此要加作用域限定符指定調(diào)用基類(lèi)的operator=,否則默認(rèn)調(diào)用子類(lèi)自己的operator=,就會(huì)陷入無(wú)限遞歸
正確示范:

錯(cuò)誤示范:

5.4 析構(gòu)函數(shù)
編譯器將子類(lèi)的析構(gòu)函數(shù)編譯完成之后,會(huì)自動(dòng)在子類(lèi)析構(gòu)函數(shù)的最后一條語(yǔ)句之后插入一條調(diào)用基類(lèi)析構(gòu)函數(shù)的匯編語(yǔ)句call ~Base();!

問(wèn)題:基類(lèi)和子類(lèi)析構(gòu)函數(shù)調(diào)用先后順序?

6、基類(lèi)中哪些成員被子類(lèi)繼承了
6.1 成員變量
普通成員變量,全部被繼承!
這個(gè)我們?cè)诒疚牡?.2 定義這個(gè)模塊已經(jīng)全部驗(yàn)證!
靜態(tài)成員變量也被繼承了
注意:靜態(tài)成員變量在整個(gè)繼承體系中只有一份
驗(yàn)證:通過(guò)靜態(tài)變量來(lái)記錄創(chuàng)建對(duì)象的個(gè)數(shù)
class Base
{
public:
Base(int a,int b)
{
_a = a;
_b = b;
++_count;
}
Base(const Base& b)
{
_a = b._a;
_b = b._b;
++_count;
}
Base& operator=(const Base& b)
{
_a = b._a;
_b = b._b;
return *this;
}
~Base()
{
cout << "Base::~Base()" << endl;
--_count;
}
public:
int _a;
int _b;
static int _count;
};
int Base::_count = 0;
class Derived : public Base
{
public:
Derived()
:Base(1,2)
{
}
Derived(int a,int b,int c)
:Base(a,b)
, _c(c)
{}
Derived(const Derived& d)
:Base(d)
{
_c = d._c;
}
Derived& operator=(const Derived& d)
{
Base::operator=(d);
_c = d._c;
return *this;
}
~Derived()
{
cout << "Derived::~Derived()" << endl;
}
public:
int _c;
};
void Test()
{
cout << &Base::_count << endl;
cout << &Derived::_count << endl;
}
6.2 成員方法
普通成員方法,被子類(lèi)繼承了。
前面的代碼均有體現(xiàn),這里不再驗(yàn)證~
靜態(tài)成員方法—也被子類(lèi)繼承了
驗(yàn)證:

7、友元函數(shù)被繼承了嗎
明確:友元函數(shù)不是類(lèi)的成員函數(shù),他只是在一個(gè)類(lèi)中進(jìn)行聲明,目的是打破類(lèi)的封裝性去訪問(wèn)原本外部不可訪問(wèn)的成員。
這個(gè)問(wèn)題很好測(cè)試,我們只需要為子類(lèi)提供一個(gè)友元函數(shù)去訪問(wèn)父類(lèi)中的protected訪問(wèn)權(quán)限的成員變量。讓一個(gè)子類(lèi)繼承自父類(lèi),然后測(cè)試在父類(lèi)中聲明的友元函數(shù)是否能夠訪問(wèn)子類(lèi)中的protected/private成員變量即可!
如果可以訪問(wèn),那就說(shuō)明 友元函數(shù)也會(huì)被繼承下來(lái)。
如果不可以訪問(wèn),那就說(shuō)明友元函數(shù)不會(huì)被繼承下來(lái)
直接上例子:

Test函數(shù)測(cè)試結(jié)果:

結(jié)論:友元函數(shù)不能被繼承!
本篇文章到這里就結(jié)束了,感覺(jué)有所幫助的讀友,可以轉(zhuǎn)發(fā)分享給身邊的朋友并留下你們的足跡!
下篇我們講講C++中一些不同的繼承體系~,我們下篇再見(jiàn)!
到此這篇關(guān)于C++深入探究繼承的概念與使用的文章就介紹到這了,更多相關(guān)C++繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)超市信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)超市信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C語(yǔ)言 枚舉類(lèi)型(Enum)詳解及示例代碼
本文主要介紹C語(yǔ)言 枚舉類(lèi)型,這里提供了詳細(xì)的相關(guān)資料及示例代碼,以便大家學(xué)習(xí)參考,有興趣的小伙伴可以參考下2016-08-08
C++實(shí)現(xiàn)選擇性排序(SelectionSort)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)選擇性排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
C語(yǔ)言 動(dòng)態(tài)分配數(shù)組案例詳解
這篇文章主要介紹了C語(yǔ)言 動(dòng)態(tài)分配數(shù)組案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
C語(yǔ)言用函數(shù)指針實(shí)現(xiàn)一個(gè)特別的計(jì)算器
函數(shù)指針是一個(gè)指針變量,它可以存儲(chǔ)函數(shù)的地址,然后使用函數(shù)指針,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言用函數(shù)指針實(shí)現(xiàn)計(jì)算器的方法,需要的朋友可以參考下2022-07-07

