欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++?繼承的范例講解

 更新時間:2022年06月06日 08:39:20   作者:林慢慢腦瓜子嗡嗡的  
繼承是C++面向?qū)ο缶幊讨械囊婚T。繼承是子類繼承父類的特征和行為,或者是繼承父類得方法,使的子類具有父類得的特性和行為。重寫是子類對父類的允許訪問的方法實行的過程進(jìn)行重新編寫,返回值和形參都不能改變。就是對原本的父類進(jìn)行重新編寫,但是外部接口不能被重寫

1.繼承的概念

繼承,是面向?qū)ο蟮娜筇匦灾弧@^承可以理解成是類級別的一個復(fù)用,它允許我們在原有類的基礎(chǔ)上進(jìn)行擴(kuò)展,增加新的功能。

當(dāng)創(chuàng)建一個類時,我們可以繼承一個已有類的成員和方法,并且在原有的基礎(chǔ)上進(jìn)行提升,這個被繼承的類叫做基類,而這個繼承后新建的類叫做派生類。

用法如下:

class [派生類名] : [繼承類型] [基類名]

例如:

class Person
{
public:
	string _name;
	int _age;
};
class Student : public Person
{
protected:
	string _stuNum;
};

這里的派生類Student就復(fù)用了Person的方法和成員,并在此基礎(chǔ)上擴(kuò)展補(bǔ)充。

2.繼承方式

繼承的方式和類的訪問限定符一樣,分為public(公有繼承),private(私有繼承), protected(保護(hù)繼承)三種。

不同的繼承方式,在派生類中繼承下來的基類成員的訪問權(quán)限也不一樣。

基類的其他成員在子類的訪問方式 = Min(成員在基類的訪問限定符,繼承方式)

備注:

1.在實際運用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因為protetced/private繼承下來的成員都只能 在派生類的類里面使用,實際中擴(kuò)展維護(hù)性不強(qiáng)。

2.使用關(guān)鍵字class時默認(rèn)的繼承方式是private,使用struct時默認(rèn)的繼承方式是public,不過最好顯示的寫出繼承方式。

3.基類與派生類的賦值轉(zhuǎn)換

派生類可以賦值給基類的對象、指針或者引用,這樣的賦值也叫做對象切割。

例如上面的Person類和Student類

這種賦值只能是派生類賦給基類(但需要割掉多出來的成員例如_ stuID),而基類對象不能賦給派生類。

基類的指針可以強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針, 如:

int main()
{
	Person p1;
	Student s1;
	Person* hPtr1 = &s1;//指向派生類對象
	Person* hPtr2 = &p1;//指向基類對象
	Student* pPtr = (Student*)hPtr1;//沒問題
	Student* pPtr = (Student*)hPtr2;//有時候沒有問題,但是會存在越界風(fēng)險
	return 0;
}

小結(jié):

1.派生類可以賦值給基類的對象、指針或者引用

2.基類對象不能賦值給派生類對象

3.基類的指針可以通過強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針。**??但是必須是基類的指針是指向派生類對象時才是安全的,否則會存在越界的風(fēng)險。**這里基類如果是多態(tài)類型,可以使用RTT的dynamic_cast來進(jìn)行識別后進(jìn)行安全轉(zhuǎn)換。

4.作用域與隱藏

??隱藏:隱藏,也叫做重定義,當(dāng)基類和派生類中出現(xiàn)重名的成員時,派生類就會將基類的同名成員給隱藏起來,然后使用自己的。(但是隱藏并不意味著就無法訪問,可以通過指明基類作用域來顯式訪問隱藏成員。)

class Person
{
public:
	void f(int age)
	{
		cout << "姓名" << _name << endl;
		cout << "年齡" << _age << endl;
	}
protected:
	string _name;
	int _age;
};
class Student : public Person
{
public:
	void f()
	{
		Person::f(32);//需顯式調(diào)用f函數(shù)
		cout << "學(xué)號" << _stuNum << endl;
	}
private:
	string _stuNum;
};

例如這里的f( )就構(gòu)成了隱藏

同時,這里還有個需要注意的問題,在基類與派生類中,同名的方法并不能構(gòu)成重載,因為處于不同的作用域中。而只要滿足方法名相同,就會構(gòu)成隱藏。

5.派生類的默認(rèn)成員函數(shù)

在每一個類中,都會有6個默認(rèn)的成員函數(shù),這些函數(shù)即使我們自己不去實現(xiàn),編譯器也會幫我們實現(xiàn)。

??這里有兩點需要注意(筆試題??迹?/p>

1.構(gòu)造函數(shù),拷貝構(gòu)造,operator=三種情況,都要調(diào)用父類對應(yīng)的構(gòu)造函數(shù)/拷貝構(gòu)造/operator=進(jìn)行對父類的成員變量的初始化,并且倘若父類沒有默認(rèn)的構(gòu)造函數(shù)的時候(比如父類寫了帶參的構(gòu)造函數(shù)),我們就要顯式調(diào)用(Person(參數(shù)…),Person::operator=(參數(shù)…))

??構(gòu)造函數(shù)顯示調(diào)用

派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)初始化基類的那一部分成員。如果基類沒有默認(rèn)的構(gòu)造函 數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。

Student()
    	:People()
	{
		cout << "Student()" << endl;
	}

??拷貝構(gòu)造顯示調(diào)用

建議拷貝構(gòu)造都用顯示調(diào)用,不然免不了出現(xiàn)子類拷貝構(gòu)造當(dāng)中調(diào)用了父類的構(gòu)造函數(shù)的情況(因為拷貝構(gòu)造也是構(gòu)造,在初始化列表處,對于子類而言,父類相當(dāng)于一個自定義類型對象,子類會調(diào)用父類的構(gòu)造函數(shù)對父類的資源進(jìn)行初始化。)

Student(const Student& s)
		:People(s)
	{
		cout << "Student(const Student& s)" << endl;
	}

??派生類的operator=必須要調(diào)用基類的operator=完成基類的復(fù)制。

Student& operator=(const Student& s)
	{
		cout << "Student& operator = (const Student& s)" << endl;
		if (this != &s)
		{
			Person:: operator=(s);
		}
	}

??析構(gòu)函數(shù)

由于編譯器會將析構(gòu)函數(shù)的名字處理成destructor,因此派生類和基類的析構(gòu)函數(shù)會構(gòu)成隱藏關(guān)系,故若要派生類要調(diào)用基類的析構(gòu)函數(shù),那么需要顯式調(diào)用,但是編譯器會默認(rèn)在派生類的析構(gòu)函數(shù)調(diào)用結(jié)束后調(diào)用基類的析構(gòu)函數(shù),這樣就析構(gòu)兩次了。

	~Person()
	{
		cout << "~Person()" << endl;
	}
	~Student()
	{
		Person:: ~Person();
		cout << "~Student()" << endl;
	}

在派生類中,基類的析構(gòu)函數(shù)會被隱藏,雖然它們這里的名字不同,但是為了實現(xiàn)多態(tài), 它們都會被編譯器重命名為destructor。在調(diào)用子類的構(gòu)造函數(shù)時,我們是先調(diào)用父類的構(gòu)造函數(shù),后對子類的成員進(jìn)行構(gòu)造。由先構(gòu)造后析構(gòu)的順序,所以我們是在析構(gòu)函數(shù)當(dāng)中析構(gòu)子類的資源,析構(gòu)函數(shù)調(diào)用完后編譯器自動幫我們調(diào)用父類的析構(gòu)函數(shù)。

6.友元與靜態(tài)成員

??1.友元

友元關(guān)系是不會繼承的,如果子類要使用父類的友元,則子類自己也要將其定義為友元。

??2.靜態(tài)成員

基類定義了static靜態(tài)成員,無論繼承了多少次,派生了多少子類,靜態(tài)成員在這整個繼承體系中有且只有一個。靜態(tài)成員不再單獨屬于某一個類亦或者是某一個對象,而是屬于這一整個繼承體系。

7.菱形繼承與虛繼承

首先簡單介紹下單繼承、多繼承的概念

單繼承:一個子類只有一個直接父類時稱這個繼承關(guān)系為單繼承

多繼承:一個子類有兩個或以上直接父類時稱這個繼承關(guān)系為多繼承

菱形繼承:菱形繼承是多繼承的一種特殊情況,下面簡單舉例介紹下菱形繼承及其帶來的二義性問題:

class Human
{
public:
	int _age;
};
class Student : public Human
{
public:
	int _stuNum;
};
class Teacher : public Human
{
public:
	int _teaNum;
};
class Assistant : public Teacher, public Student
{
};

哦豁?。?!菱形繼承這個關(guān)系感受到了吧?。?!

??直接講下這個菱形繼承帶來的二義性問題:

按照道理來說,各個類的大小應(yīng)該是這樣的。human類4個字節(jié),teacher和student都是8個字節(jié),而assistant是12個字節(jié),但是實際上assistant卻是16字節(jié)。

??為什么assistant會有16字節(jié)?

這就是菱形繼承的數(shù)據(jù)冗余和二義性問題的體現(xiàn)。

這里的teacher和student都從human中繼承了相同的成員 _age。但是assistant再從teacher和student繼承時,就分別把這兩個 _age都給繼承了過來,導(dǎo)致這里有了兩個一樣的成員。

在這樣的情況下,后續(xù)想給 _age賦值,也會被編譯器提示指示不明確,報錯。

??菱形繼承的二義性是很致命的問題,如何解決呢?

虛繼承,在腰部的類繼承時添加virtual關(guān)鍵字。

class Student : virtual public Human
{
public:
	int _stuNum;
};
class Teacher : virtual public Human
{
public:
	int _teaNum;
};
class Assistant : public Teacher, public Student
{
};

這次,二義性問題解決了,teacher和student都是12個字節(jié),而assistant是20個字節(jié)。

想知道為什么?點這里:從內(nèi)存角度看待虛繼承

??簡單小結(jié)一下

1.可以看到?jīng)]有虛繼承的情況下,Assitant中的成員連續(xù)排列出現(xiàn)了Teacher和Student中的_age是兩個不同的值,但實際上一個人不會有兩個年齡,所以這就出現(xiàn)了數(shù)據(jù)冗余。

2.這里多出來的8個字節(jié),其實是兩個虛基表指針。因為這里Human中的 _age是 teacher和 student共有的,所以為了能夠方便處理,在內(nèi)存中分布的時候,就會把這個共有成員 _age放到對象組成的最末尾的位置。然后通過了Teacher和Student的兩個指針,指向的一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表。虛基表中存的偏移量。通過偏移量可以找到下面的Human。由此可見,使用了虛擬繼承后,就可以解決菱形繼承導(dǎo)致的問題。

??為什么Teacher、Student需要去找屬于自己的 _age?

基類與派生類的賦值轉(zhuǎn)換時,需要進(jìn)行切片。

int main()
{
	Assistant a;
	Teacher t = a; 
	Student s = a;
	return 0;
}

當(dāng)把對象a賦值給t和s的時候,因為他們互相沒有對方的 _stuNum和 _teaNum,所以他們需要進(jìn)行對象的切割,但是又因為 _age存放在對象的最尾部,所以只有知道了自己的偏移量,才能夠成功的在切割了沒有的元素時,還能找到自己的 _age。

8.繼承和組合

??繼承是一種復(fù)用的方式,但不是唯一方式!

1.public繼承是一種is-a的關(guān)系,就是基類是一個大類,而派生類則是這個大類中細(xì)分出來的一個子類,但是他們本質(zhì)上其實是一種東西。

2.組合是一種has-a的關(guān)系,就是一種包含關(guān)系,比如對象a是對象b的成員,那么他們的關(guān)系就是對象b的組成中包含了對象a,對象a是對象b中的一部分,對象b包含對象a。

3.繼承方式的復(fù)用常稱之為白箱復(fù)用,在繼承方式中,基類的內(nèi)部細(xì)節(jié)對子類可見,這一定程度上破壞了基類的封裝,伴隨著基類的改變,對派生類的改變很大。并且兩者依賴關(guān)系強(qiáng),耦合度大。

4.對象組合式繼承之外的復(fù)用選擇,對象組合要求被組合對象提供良好的接口定義。這種復(fù)用稱之為黑箱復(fù)用,對象的內(nèi)部實現(xiàn)細(xì)節(jié)是不可見的。耦合度低。

實際工程中能用繼承和組合就用組合,組合的耦合度低,代碼的維護(hù)性好,但是繼承在有些關(guān)系就適合用繼承就用繼承,并且要實現(xiàn)多態(tài)就一定要用繼承。

到此這篇關(guān)于C++ 繼承的范例講解的文章就介紹到這了,更多相關(guān)C++ 繼承內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt開發(fā)之QTreeWidget的使用教程詳解

    Qt開發(fā)之QTreeWidget的使用教程詳解

    這篇文章主要為大家詳細(xì)介紹了Qt中QTreeWidget使用的相關(guān)資料,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Qt有一定的幫助,感興趣的小伙伴可以了解一下
    2022-12-12
  • C語言宏定義使用分析

    C語言宏定義使用分析

    在宏定義中,“宏名稱”和“宏字符串”是通過“空格”來區(qū)分的,某些朋友不要混淆了,接下來請祥看本文
    2012-12-12
  • C語言中strlen()函數(shù)的使用詳解

    C語言中strlen()函數(shù)的使用詳解

    strlen函數(shù)是用來求字符串長度的函數(shù),這個函數(shù)遇到‘\0’就會停止,且這個長度不包含‘\0’,這篇文章給大家介紹了C語言中strlen()函數(shù)的使用,感興趣的朋友一起看看吧
    2024-02-02
  • 深入了解C語言字符函數(shù)和字符串函數(shù)

    深入了解C語言字符函數(shù)和字符串函數(shù)

    這篇文章主要給大家介紹了關(guān)于C語言字符/字符串的相關(guān)函數(shù),文中通過示例代碼總結(jié)的非常詳細(xì),對大家學(xué)習(xí)或者使用C語言具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • VS中PCL庫附加依賴項配置過程解析

    VS中PCL庫附加依賴項配置過程解析

    這篇文章主要介紹了VS中PCL庫附加依賴項配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • 淺析C++淺拷貝與深拷貝的聯(lián)系和區(qū)別

    淺析C++淺拷貝與深拷貝的聯(lián)系和區(qū)別

    在c++中,深拷貝和淺拷貝也算是一個難點,特別是對于初學(xué)者來說,往往在不知道兩者區(qū)別的情況下而錯誤的使用了淺拷貝,從而導(dǎo)致了野指針之類的問題,但是又因為缺少理解所以很難定位到問題所在
    2022-09-09
  • C語言16進(jìn)制與ASCII字符相互轉(zhuǎn)換

    C語言16進(jìn)制與ASCII字符相互轉(zhuǎn)換

    大家好,本篇文章主要講的是C語言16進(jìn)制與ASCII字符相互轉(zhuǎn)換,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • C++實現(xiàn)將輸入的內(nèi)容輸出到文本文件

    C++實現(xiàn)將輸入的內(nèi)容輸出到文本文件

    這篇文章主要介紹了C++實現(xiàn)將輸入的內(nèi)容輸出到文本文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • c++超細(xì)致講解引用

    c++超細(xì)致講解引用

    引用(reference)就是C++對C語言的重要擴(kuò)充。引用就是某一變量(目標(biāo))的一個別名,對引用的操作與對變量直接操作完全一樣
    2022-05-05
  • C++可調(diào)用對象callable object深入分析

    C++可調(diào)用對象callable object深入分析

    所謂的callable object,表示可以被某種方式調(diào)用其某些函數(shù)的對象。它可以是:一個函數(shù)、一個指向成員函數(shù)的指針、一個函數(shù)對象,該對象擁有operator()、一個lambda表達(dá)式,嚴(yán)格的說它是一種函數(shù)對象
    2022-08-08

最新評論