- 繼承的概念
繼承是使得面向對象程序設計使代碼可以複用的主要手段,可以在保持原有類的基礎上進行擴展,這樣產生的類叫派生類,也叫子類,原來的類叫基類也叫父類,繼承是類設計層次的複用。
語法格式爲
class person //基類
{
public:
........
protected:
string _name = "C++";
int _age = 35;
};
class student :public person//student 爲派生類
{....
}
語法爲class/struct + 派生類名字+:+繼承方式+基類名字
繼承方式有三類 private,public,protected
如果繼承方式不寫,class默認爲private繼承,struct默認爲public繼承。
繼承規則遵循同小取小,基類的private在public中不開見。
例如假如是protected繼承,則基類的public的成員在派生類中被視爲protected成員,如果是public繼承,則基類的private不可見,其他的成員訪問權限不會變化。
總結
- 基類的private成員在派生類中是不可見的,不可見指基類的私有成員被繼承到派生類對象中,但語法限制派生類對象不管是類裏面,還是類外面都不能訪問。
- 在實際的運用中一般是public繼承,很少用protected/private,因爲實際中擴展維護性不強。
2.基類和派生類對象賦值轉換
派生類對象可以賦值給基類的對象/指針/引用,叫做切片或切割,意思是把派生類的那部分切過去賦值。例如
class person
{
public:
person(const string &name = "C++", const int &age = 35)
{
_name = name;
_age = age;
}
void print()
{
cout << _name<< endl;
cout << _age << endl;
}
protected:
string _name = "C++";
int _age = 35;
};//基類
class student :public person
{
public:
student(int stuid=123456) :person("java", 23)
{
_stuid = stuid;
}
void print()
{
cout << _name << endl;
cout << _age << endl;
cout << _stuid << endl;
}
void ccc()
{
cout << _stuid;
}
int _stuid = 23;
protected:
};//派生類
void test1()
{
person m;
student n;
n.print();
m = n;
m.print();
person *dd1 = &n;
dd1->print();
person &dd2 = n;
dd2.print();
}
可以想象如下圖
相當於只給基類需要的屬性,將不需要的切掉了。
如果想把基類的賦值給子類,需要通過強制類型限制賦值給指針或者引用(底層的實現還是指針),
void test2()
{
person mm;
person *msl = &mm;
student nn;
student *nsl = (student*)&mm;//可能有越界訪問的問題
nsl->print();
}
3.繼承中的作用域
- 在繼承體系中基類和派生類有獨立的作用域
- 子類和父類中有同名成員,子類成員將屏蔽父類對同名成員的直接訪問,這種情況叫隱藏,也叫重定義,可以類比局部變量覆蓋了全局變量。
- 要注意成員函數,函數名相同就能構成隱藏
- 儘量避免繼承體系中定義同名的成員
例如上面的person和student的print成員函數實際上已經構成了隱藏。
4.派生類的默認成員函數
在C++中我們知道默認函數有四個分別爲構造函數,拷貝構造函數,賦值函數,析構函數。
在繼承體系下的默認成員函數有以下結幾個特點
- 派生類的構造函數必須調用基類的構造函數初始化基類的那一部分成員。如果基類沒有默認的構造函數,則必須在派生類的構造函數的初始化列表階段顯示調用
- 派生類的拷貝構造函數必須調用基類的拷貝構造函數完成基類的拷貝構造
- 同理operator=也要調用基類的operator=
- 派生類的析構函數會自動調用基類的析構函數清理基類成員,如果顯式調用反而會出錯。
- 派生類對象初始化先調用基類構造在調用派生類
- 派生類對象析構先調用派生類析構再調用基類析構,調用順序和棧的思想有些類似。
5繼承與友元
友元關係不能繼承,也就是說基類友元不能訪問子類私有和保護成員,同時基類的private成員在派生類中不可見,所以派生類的友元也不能訪問基類的private成員
6繼承與靜態成員
基類定義了static靜態成員,則整個繼承體系裏面只有一個靜態成員,C++static屬於所有的對象