C++里面的繼承
- 1.什么是繼承以及怎樣繼承
- 1.1 定義
- 1.2 繼承格式與方式
- 2. 基類物件與派生類物件之間的賦值轉換(公有繼承)
- 3. 作用域的理解
- 4. 派生類的默認成員函式
- 5. 繼承與友元,繼承與靜態成員
- 6. 菱形繼承和菱形虛擬繼承
- 7. 組合和繼承區別
1.什么是繼承以及怎樣繼承
1.1 定義
- 繼承機制是面型物件程式設計使代碼復用的最重要的手段,繼承是類設計層次的復用,它是在保持原有類特性的基礎上進行擴展,增加功能,這樣產生新的類,稱為派生類,
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "gkk"; // 姓名
int _age = 22; // 年齡
};
class Student : public Person //繼承
{
protected:
int _snum; // 學號
};
class Teacher : public Person //繼承
{
protected:
int _jobid; // 工號
};
int main()
{
Student s;
Teacher t;
s.Printf();
s.Printf();
return 0;
}
- 繼承后父類的Person的成員(成員函式+成員變數)都會變成子類的一部分,這里體現出了Student和Teacher復用了Person的成員,下面我們使用監視視窗查看Student和Teacher物件,可以看到變數的復用.
1.2 繼承格式與方式
-
定義格式:
-

-
當不同的成員以不同的方式繼承時訪問方式的變化:

注意:
1.基類private成員在派生類中無論以什么方式繼承都是不可見的,(只是不能訪問,依然被繼承)
2. 要在派生類中訪問基類成員,而保證不在類外直接訪問,可以將成員定義為protected,
3 struct默認繼承是public,class默認private,
2. 基類物件與派生類物件之間的賦值轉換(公有繼承)
- 切片:派生類物件 可以賦值給 基類的物件 / 基類的指標 / 基類的參考,
- 基類物件不能賦值給派生類物件
- 基類的指標可以通過強制型別轉換賦值給派生類的指標,但是必須是基類的指標是指向派生類物件時才是安全的,

3. 作用域的理解
- 基類和派生類都有獨立的作用域,
- 隱藏(重定義):子類和父類中有同名成員,子類成員將屏蔽父類對同名成員的直接訪問, 解決辦法:(在子類成員函式中基類::基類成員 顯示訪問)
- 隱藏只要函式名相同就構成隱藏,(要注意的是隱藏和多載不同,因為作用域不同,)
5.在實際中盡量避免定義同名函式,
4. 派生類的默認成員函式
6個默認成員函式,“默認”的意思就是指我們不寫,編譯器會變我們自動生成一個,那么在派生類中,這幾個成員函式是如何生成的呢?

- 派生類的建構式必須呼叫基類的建構式初始化基類的那一部分成員,如果基類沒有默認的建構式,則必須在派生類建構式的初始化串列階段顯示呼叫,
- 派生類的拷貝建構式必須呼叫基類的拷貝構造完成基類的拷貝初始化,
- 派生類的operator=必須要呼叫基類的operator=完成基類的復制,
- 派生類的解構式會在被呼叫完成后自動呼叫基類的解構式清理基類成員,因為這樣才能保證派生類物件先清理派生類成員再清理基類成員的順序,
- 派生類物件初始化先呼叫基類構造再調派生類構造,
- 派生類物件析構清理先呼叫派生類析構在呼叫基類的析構,

5. 繼承與友元,繼承與靜態成員
- 友元關系不能繼承,也就是說基類的友元不能訪問子類的私有和保護成員,(比如:你父親的朋友不一定是你的朋友)
- 基類定義了static靜態成員,則整個繼承體系里面只有一個這樣的成員,無論派生出多少個子類,都只有一個static成員實體 ,
6. 菱形繼承和菱形虛擬繼承

- 菱形繼承會有資料冗余和二義性問題,

- 虛擬繼承可以解決菱形繼承的二義性和資料冗余的問題,

- 虛擬繼承解決資料冗余和二義性的原理
- 為了研究虛擬繼承原理,我們給出了一個簡化的菱形繼承繼承體系,再借助記憶體視窗觀察物件成員的模型:
class A {
public:
int _a;
};
// class B : public A
class B : virtual public A {
public:
int _b;
};
// class C : public A
class C : virtual public A {
public:
int _c;
};
class D : public B, public C {
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}


7. 組合和繼承區別
1.組合定義
在新類里面創建原有類的物件,重復利用已有類的功能,(has-a關系)
// Tire(輪胎)和Car(汽車)構成has-a的關系
class Tire{
protected:
string _brand = "Michelin"; // 品牌
size_t _size = 17; // 尺寸
};
class Car{
protected:
string _colour = "白色"; // 顏色
string _num = "陜ABIT00"; // 車牌號
Tire _t; // 輪胎
};
2.繼承定義
可以使用現有類的功能,并且在無需重復撰寫原有類的情況下對原有類進行功能上的擴展,(is-a關系)
3.兩種方式的選擇
- 物件組合是類繼承之外的另一種復用選擇,新的更復雜的功能可以通過組裝或組合物件來獲得,物件組合要求被組合的物件具有良好定義的介面,這種復用風格被稱為黑箱復用(black-box reuse),因為物件的內部細節是不可見的,物件只以“黑箱”的形式出現, 組合類之間沒有很強的依賴關系,耦合度低,優先使用物件組合有助于你保持每個類被封裝,
- 實際盡量多去用組合,組合的耦合度低,代碼維護性好,不過繼承也有用武之地的,有些關系就適合繼承那就用繼承,另外要實作多型,也必須要繼承,類之間的關系可以用繼承,可以用組合,就用組合,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282343.html
標籤:其他

