最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++?繼承的范例講解

 更新時間:2022年06月06日 08:39:20   作者:林慢慢腦瓜子嗡嗡的  
繼承是C++面向對象編程中的一門。繼承是子類繼承父類的特征和行為,或者是繼承父類得方法,使的子類具有父類得的特性和行為。重寫是子類對父類的允許訪問的方法實行的過程進行重新編寫,返回值和形參都不能改變。就是對原本的父類進行重新編寫,但是外部接口不能被重寫

1.繼承的概念

繼承,是面向對象的三大特性之一。繼承可以理解成是類級別的一個復用,它允許我們在原有類的基礎上進行擴展,增加新的功能。

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

用法如下:

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

例如:

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

這里的派生類Student就復用了Person的方法和成員,并在此基礎上擴展補充。

2.繼承方式

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

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

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

備注:

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

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

3.基類與派生類的賦值轉換

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

例如上面的Person類和Student類

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

基類的指針可以強制類型轉換賦值給派生類的指針, 如:

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

小結:

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

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

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

4.作用域與隱藏

??隱藏:隱藏,也叫做重定義,當基類和派生類中出現(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);//需顯式調用f函數(shù)
		cout << "學號" << _stuNum << endl;
	}
private:
	string _stuNum;
};

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

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

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

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

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

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

??構造函數(shù)顯示調用

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

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

??拷貝構造顯示調用

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

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

??派生類的operator=必須要調用基類的operator=完成基類的復制。

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

??析構函數(shù)

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

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

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

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

??1.友元

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

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

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

7.菱形繼承與虛繼承

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

單繼承:一個子類只有一個直接父類時稱這個繼承關系為單繼承

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

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

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
{
};

哦豁?。?!菱形繼承這個關系感受到了吧?。?!

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

按照道理來說,各個類的大小應該是這樣的。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都給繼承了過來,導致這里有了兩個一樣的成員。

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

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

虛繼承,在腰部的類繼承時添加virtual關鍵字。

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é)。

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

??簡單小結一下

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

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

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

基類與派生類的賦值轉換時,需要進行切片。

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

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

8.繼承和組合

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

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

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

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

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

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

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

相關文章

  • C語言之飛機大戰(zhàn)游戲

    C語言之飛機大戰(zhàn)游戲

    這篇文章主要為大家詳細介紹了C語言之飛機大戰(zhàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • C語言實現(xiàn)旅游資訊管理系統(tǒng)

    C語言實現(xiàn)旅游資訊管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)旅游資訊管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言文件操作大全

    C語言文件操作大全

    這篇文章主要介紹了C語言文件操作大全的相關資料,需要的朋友可以參考下
    2018-03-03
  • C語言結構體版學生成績管理系統(tǒng)

    C語言結構體版學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言結構體版的學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • C++詳細講解圖的遍歷

    C++詳細講解圖的遍歷

    圖的遍歷是指,從給定圖中任意指定的頂點(稱為初始點)出發(fā),按照某種搜索方法沿著圖的邊訪問圖中的所有頂點,使每個頂點僅被訪問一次,這個過程稱為圖的遍歷
    2022-05-05
  • C++?ncnn模型驗證精度實現(xiàn)代碼

    C++?ncnn模型驗證精度實現(xiàn)代碼

    這篇文章主要介紹了C++?ncnn模型驗證精度實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-02-02
  • 淺談C++11中=delete的巧妙用法

    淺談C++11中=delete的巧妙用法

    本文主要介紹了C++11中=delete的巧妙用法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++中sort函數(shù)的基礎入門使用教程

    C++中sort函數(shù)的基礎入門使用教程

    這篇文章主要給大家介紹了關于C++中sort函數(shù)的基礎入門使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用C++具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2018-12-12
  • C語言算法練習之抓交通肇事犯

    C語言算法練習之抓交通肇事犯

    這篇文章主要該大家分享C語言算法抓交通肇事犯的練習,文章主要通過描述抓交通肇事犯得問題然后確定程序框架將結果運算出來,下面來看詳細內容吧,需要的朋友可以參考一下
    2022-03-03
  • C語言實現(xiàn)在windows服務中新建進程的方法

    C語言實現(xiàn)在windows服務中新建進程的方法

    這篇文章主要介紹了C語言實現(xiàn)在windows服務中新建進程的方法,涉及C語言進程操作的相關技巧,需要的朋友可以參考下
    2015-06-06

最新評論

台南市| 长治县| 盐城市| 太仓市| 瑞安市| 海兴县| 班玛县| 泾川县| 贵德县| 驻马店市| 夏河县| 天镇县| 翁源县| 涞水县| 易门县| 正定县| 宁陵县| 邯郸市| 扶沟县| 松潘县| 科尔| 溆浦县| 安宁市| 玉田县| 靖安县| 株洲县| 沂源县| 澄迈县| 盐边县| 都兰县| 平舆县| 长丰县| 政和县| 郎溪县| 永吉县| 金坛市| 靖宇县| 望江县| 台东县| 仪陇县| 丹棱县|