網(wǎng)站調(diào)用接口怎么做新站點seo聯(lián)系方式
(?′??)(●'?'●)╰(*°▽°*)╯(*/ω\*)(^///^)(?′?
?)(?′??)(●'?'●)╰(*°▽°*)╯(*/ω\*)(?′?
?)(●’?’●)╰(°▽°)╯(/ω\)(///)
C++:繼承:面向?qū)ο缶幊痰闹匾匦?/h4> - 前言
- **繼承**
- 1.繼承的概念及定義
- 1.1繼承的概念
- 1.2繼承的定義
- 1.2.1定義的格式
- 1.2.2繼承關(guān)系和訪問限定符
- 1.2.3繼承后基類(父類)成員訪問方式的變化
- 2.基類和派生類對象賦值轉(zhuǎn)換
- 3.繼承中的作用域
- 4.派生類的默認成員函數(shù)
- 5.繼承與友元
- 6. 繼承與靜態(tài)成員
- 7.多繼承與菱形繼承和菱形虛擬繼承
- 前言
- **繼承**
- 1.繼承的概念及定義
- 1.1繼承的概念
- 1.2繼承的定義
- 1.2.1定義的格式
- 1.2.2繼承關(guān)系和訪問限定符
- 1.2.3繼承后基類(父類)成員訪問方式的變化
- 2.基類和派生類對象賦值轉(zhuǎn)換
- 3.繼承中的作用域
- 4.派生類的默認成員函數(shù)
- 5.繼承與友元
- 6. 繼承與靜態(tài)成員
- 7.多繼承與菱形繼承和菱形虛擬繼承
🎉文章簡介:
🎉本篇文章將 C++繼承,全特化,偏特化,非類型模板參數(shù),模板的分離編譯 相關(guān)知識進行分享!
💕如果您覺得文章不錯,期待你的一鍵三連哦!!!
前言
在這篇文章中,你可以學習到繼承作為面向?qū)ο缶幊痰闹匾匦?#xff0c;它允許一個類(子類)繼承另一個類(父類)的屬性和方法。
在文章中涵蓋的主要內(nèi)容:
繼承的概念,繼承的語法,繼承的作用,單繼承,多繼承,菱形繼承,菱形虛擬繼承,菱形虛擬繼承與菱形繼承在內(nèi)存中的差異等。
繼承
1.繼承的概念及定義
1.1繼承的概念
繼承是面向?qū)ο蟪绦蛟O計使代碼可以復用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進行擴展,增加功能,這樣產(chǎn)生新的類,稱派生類。簡單地說就是類的復用;
1.2繼承的定義
1.2.1定義的格式
舉個栗子(下附代碼):
代碼段:
class Person
{
protected: string _name;int _age;string _sex;int _tel;
};
class student:public Person //student繼承了Person這個類
{
protected:int _id;
};
1.2.2繼承關(guān)系和訪問限定符
1.2.3繼承后基類(父類)成員訪問方式的變化
類成員/繼承方式 | public繼承 | protected繼承 | private繼承 |
---|---|---|---|
基類的public成員 | 派生類的public成員 | 派生類的protected成員 | 派生private成員 |
基類的protected成員 | 派生類的protected成員 | 派生類的protected成員 | 派生類的private成員 |
基類的private成員 | 在派生類中不可見 | 在派生類中不可見 | 在派生類中不可見 |
總結(jié):
1.基類的private成員在派生類中無論以什么方式繼承都是不可見的,這里的不可見是指基類的私有成員還是被繼承到了派生類對象中,但是語法上限制派生類對象不管在類里面還是類外面都不能去訪問它;
2.基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected??梢钥闯霰Wo成員限定符是因繼承才出現(xiàn)的;
3.實際上面的表格我們進行一下總結(jié)會發(fā)現(xiàn),基類的私有成員在子類都是不可見。基類的其他成員在子類的訪問方式 == Min(成員在基類的訪問限定符,繼承方式),public > protected > private;
4.使用關(guān)鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過最好顯示的寫出繼承方式;
5.在實際運用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因為protetced/private繼承下來的成員都只能在派生類的類里面使用,實際中擴展維護性不強;
舉個栗子:
從上面例子可以看出,private繼承后,public,protected成員在派生類可以訪問,private成員不可訪問;
2.基類和派生類對象賦值轉(zhuǎn)換
派生類對象 可以賦值給 基類的對象 / 基類的指針 / 基類的引用。這里有個形象的說法叫切片或者切割。
基類對象不能賦值給派生類對象。
基類的指針或者引用可以通過強制類型轉(zhuǎn)換賦值給派生類的指針或者引用。注意:但是必須是基類的指針是指向派生類對象時才是安全的。這里基類如果是多態(tài)類型,會有特殊處理(后面的文章會提到);
class Person
{
protected: string _name;int _age;string _sex;int _tel;
};
class student:public Person
{
protected:int _id;
};int main()
{student s1;Person p1;p1 = s1;//s1 = p1; //這里不能基類給派生類Person& pp1 = s1; //是對截斷后的內(nèi)容引用Person* pp2 = &s1; //指向的是截斷后的內(nèi)容student* ss;ss = (student*)&p1; //基類的指針可以通過強制類型轉(zhuǎn)換賦值給派生類的指針return 0;
}
3.繼承中的作用域
1. 在繼承體系中基類和派生類都有獨立的作用域;
(就憑這一點,因此兩個域中的函數(shù)不能構(gòu)成函數(shù)重載)
2. 子類和父類中有同名成員,子類成員將屏蔽父類對同名成員的直接訪問,這種情況叫隱藏,也叫重定義。(在子類成員函數(shù)中,可以使用 基類::基類成員 顯示訪問)
3. 需要注意的是如果是成員函數(shù)的隱藏,只需要函數(shù)名相同就構(gòu)成隱藏。
4. 注意在實際中在繼承體系里面最好不要定義同名的成員。
4.派生類的默認成員函數(shù)
派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)初始化基類的那一部分成員。如果基類沒有默認的構(gòu)造函數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。(先父后子)
派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
派生類的operator=必須要調(diào)用基類的operator=完成基類的復制。
派生類的析構(gòu)函數(shù)會在被調(diào)用完成后自動調(diào)用基類的析構(gòu)函數(shù)清理基類成員。因為這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。(先子后父)
編譯器會對析構(gòu)函數(shù)名進行特殊處理,處理成destrutor(),所以父類析構(gòu)函數(shù)不加virtual的情況下,子類析構(gòu)函數(shù)和父類析構(gòu)函數(shù)構(gòu)成隱藏關(guān)系。
如果要顯示調(diào)用,需要指定作用域;
5.繼承與友元
友元關(guān)系不能被繼承,也就是說基類友元不能訪問子類私有和保護成員
舉個例子:
6. 繼承與靜態(tài)成員
基類定義了static靜態(tài)成員,則整個繼承體系里面只有一個這樣的成員。因為靜態(tài)成員函數(shù)不是放在類里面的,而是放在靜態(tài)區(qū)的,是這個類的對象所公有的,無論派生出多少個子類,都只有一個static成員實例 ;
利用這個特性,可以統(tǒng)計這個類被創(chuàng)建了多少個對象;
如果被繼承了,無論派生類實例化出對象了還是基=基類實例化出對象都會調(diào)用基類的構(gòu)造函數(shù),就可以統(tǒng)計出個數(shù);
例子:
class Person
{
public:Person(){_count++;}
protected: int _age;
public:static int _count;
};
int Person::_count = 0;class student:public Person
{
public:student(){}
protected:int _id;
};int main()
{student S1;student S2;Person P1;Person P2;cout << Person::_count << endl; //打印結(jié)果為4return 0;
}
7.多繼承與菱形繼承和菱形虛擬繼承
單繼承:一個子類只有一個直接父類時稱這個繼承關(guān)系為單繼承
多繼承:一個子類只有多個直接父類時稱這個繼承關(guān)系為多繼承
菱形繼承:
菱形繼承的問題:菱形繼承有數(shù)據(jù)冗余和二義性的問題。在D的對象中A成員會有兩份。因為B,C中都繼承了A,里面各有一份A,然后D繼承了B和C,所以會有兩份A;
因為有兩份,所以數(shù)據(jù)冗余了,又因為D里面有兩份A的成員,如果想通過D實例化的對象去訪問B中繼承的A的成員時,不知道是去訪問B的還是C的;結(jié)合下面例子看看:
結(jié)合下面代碼:
class A
{
public:int _a;
};
class B:public A
{
protected:int _b;
};
class C:public A
{
protected:int _c;
};
class D:public B, public C
{
protected:int _d;
};
int main()
{D dd;//dd._a = 10; //會報錯(訪問不明確)dd.B::_a = 10;dd.C::_a = 100; //這樣指定類域訪問也可以,但是代碼稍許冗余return 0;
}
解決方法:
虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問題。如上面的繼承關(guān)系,在B和C的繼承A時使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用。
解決后的代碼:
class A
{
public:int _a;
};
class B:virtual public A /這里+
{
protected:int _b;
};
class C:virtual public A //這里+
{
protected:int _c;
};
class D:public B, public C
{
protected:int _d;
};
在哪里+virtual的問題
在造成數(shù)據(jù)冗余的那兩個類的繼承方式前面加virtual
比如:
菱形繼承和虛擬菱形繼承在內(nèi)存上的差異
我們討論的是VS上
D對象中將A放到的了對象組成的最下面,這個A同時屬于B和C,那么B和C如何去找到公共的A呢?這里是通過了B和C的兩個指針,指向的一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表。虛基表中存的偏移量。通過偏移量可以找到下面的A。
(?′??)(●'?'●)╰(*°▽°*)╯(*/ω\*)(^///^)(?′?
?)(●’?’●)