深度揭秘C++面向?qū)ο缶幊讨欣^承的核心概念
一.繼承
1.繼承與面向?qū)ο?/h3>
我們知道C語言是面向過程的編程語言,C++在C語言的基礎(chǔ)上進(jìn)化出了面向?qū)ο蟮哪P?。而繼承就是面向?qū)ο蟮闹匾獙傩?。繼承使得我們?cè)谝粋€(gè)基礎(chǔ)屬性上能夠加以拓展,用來描述很多具有相同基本屬性又各有不同的事務(wù)。
2.繼承方式訪問權(quán)限
繼承方式與訪問權(quán)限相同都有三種:public、private、protected繼承,再結(jié)合基類的三種訪問權(quán)限,在派生類中就有九種不同的情況,可以總結(jié)為:基類為私有的成員在派生類一律不可見,其余權(quán)限按照與繼承方式相比較小的來。
3.切片(賦值轉(zhuǎn)換)
在實(shí)際應(yīng)用場(chǎng)景中我們常用基類代表幾種事務(wù)共同的基本屬性,派生類用來代表自己獨(dú)特的屬性,這就會(huì)導(dǎo)致派生類對(duì)象一定是包含父類對(duì)象的,所以子類對(duì)象可以賦給父類對(duì)象/指針/引用,過程會(huì)將子類中獨(dú)特屬性的成員切出,剩余賦給父類對(duì)象,所以稱為切片,不僅如此基類的指針可以通過強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針,代碼演示如下:
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student : public Person
{
public:
int _No;
};
void Test()
{
Student sobj;
// 子類對(duì)象可以賦值給父類對(duì)象/指針/引用
Person pobj = sobj;
Person* pp = &sobj;
Person& rp = sobj;
// 基類的指針可以通過強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針
pp = &sobj;
Student * ps1 = (Student*)pp; // 這種情況轉(zhuǎn)換時(shí)可以的。
ps1->_No = 10;
pp = &pobj;
Student* ps2 = (Student*)pp; // 這種情況轉(zhuǎn)換時(shí)雖然可以,但是會(huì)存在越界訪問的問
ps2->_No = 10;
}
int main()
{
Test();
return 0;
}4.作用域
如果在基類和派生類定義了同名函數(shù)就會(huì)構(gòu)成隱藏/重定義,子類成員將屏蔽父類對(duì)同名成員的直接訪問,如下所示;
class A
{
public:
A(int num = 0)
:_num(num)
{}
void func()
{
cout << _num << endl;
}
private:
int _num;
};
class B : public A
{
public:
B(int val = 1)
:_val(val)
{}
void func()
{
cout << _val<< endl;
}
private:
int _val;
};
int main()
{
B b;
b.func();
b.A::func();
return 0;
}5.默認(rèn)成員函數(shù)
繼承這里遵循著一個(gè)規(guī)則:構(gòu)造先父后子,析構(gòu)先子后父。因?yàn)榕缮愔幸欢ò惖膶?duì)象所以派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)初始化基類的那一部分成員,如果基類沒有默認(rèn)的構(gòu)造函數(shù)(無參、全缺省、編譯器默認(rèn)生成),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。
派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
派生類的operator=必須要調(diào)用基類的operator=完成基類的復(fù)制。
基類的析構(gòu)函數(shù)調(diào)用后會(huì)自動(dòng)調(diào)用基類的析構(gòu)函數(shù),不能在派生類顯示調(diào)用不然無法保證析構(gòu)先子后父的順序。
6.友元與靜態(tài)函數(shù)
友元關(guān)系不會(huì)繼承,靜態(tài)函數(shù)不會(huì)多次實(shí)例化。
7.解決菱形繼承的二義性與數(shù)據(jù)冗余
菱形繼承是多繼承的一種特殊情況,我們?cè)诰帉懘a時(shí)應(yīng)要避免菱形繼承:

如上圖所示就是一個(gè)菱形繼承,這樣會(huì)導(dǎo)致A類中會(huì)有兩份P類中的成員,這樣不僅會(huì)浪費(fèi)空間,而且會(huì)產(chǎn)生二義性,如果我通過A對(duì)象訪問P中的成員,因?yàn)锳類中有兩份P中的成員所有會(huì)有歧義。為了解決此問題,出現(xiàn)了虛擬繼承。如下圖所示:

那虛繼承是如何完成的呢:在d類中建立虛基表,將原來冗余的對(duì)象放在d對(duì)象空間最下面,B、C原來存儲(chǔ)A的位置存儲(chǔ)當(dāng)前位置與空間最下面A對(duì)象的偏移量,保證指定B或者C對(duì)象訪問_a時(shí)都能訪問到。
8.繼承與組合
與繼承相比組合的耦合度更低,更適合我們使用!繼承又稱為白箱復(fù)用,組合稱為黑盒復(fù)用,因?yàn)槭褂媒M合的話是無法看到類內(nèi)部的設(shè)計(jì)。

到此這篇關(guān)于深度揭秘C++面向?qū)ο缶幊讨欣^承的核心概念的文章就介紹到這了,更多相關(guān)C++繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++17文件系統(tǒng)庫之std::filesystem 示例詳解
std::filesystem是C++17引入的一個(gè)強(qiáng)大且易用的文件系統(tǒng)操作庫,它提供了跨平臺(tái)的文件系統(tǒng)操作接口,簡(jiǎn)化了文件和目錄操作的代碼實(shí)現(xiàn),本文給大家介紹C++17文件系統(tǒng)庫之std::filesystem 示例詳解,感興趣的朋友一起看看吧2025-03-03
C++實(shí)現(xiàn)LeetCode(60.序列排序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(60.序列排序),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++實(shí)現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)的數(shù)學(xué)算法
這篇文章和大家分享一下我個(gè)人對(duì)十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)的想法,目前暫時(shí)更新只整數(shù)十進(jìn)制的轉(zhuǎn)換,后續(xù)會(huì)更新帶有小數(shù)的進(jìn)制轉(zhuǎn)換,代碼使用c++實(shí)現(xiàn)2021-09-09

