什麼是繼承
繼承機制是面向對象程序設計使用代碼可以複用的重要手段,它允許程序員保持原有類的特性的基礎上進行擴展,增加功能,這樣產生的新的類,稱爲派生類。繼承呈現了面向對象程序設計的層次結構,體現了由簡單到複雜認知的過程。繼承是類設計層次的複用。
繼承方式
- public繼承
- protect繼承
- private繼承
類成員/繼承方式 | public繼承 | protect繼承 | private繼承 |
---|---|---|---|
基類的public成員 | 派生類public成員 | 派生類protected成員 | 派生類private成員 |
基類的proteced成員 | 派生類protected成員 | 派生類protected成員 | 派生類private成員 |
基類的private成員 | 在派生類中不可見 | 在派生類中不可見 | 在派生類中不可見 |
- 基類private成員在派生類中無論以什麼方式繼承都是不可見的。這裏的不可見是指基類的私有成員還是被繼承到派生類對象中,但是語法上限制派生類對象不管在類裏面還是類外都是不能去訪問它。
- 使用關鍵字class時默認的繼承方式是private,使用struct時的默認方式是public,不過最好顯示的寫出繼承方式
- 在實際運用中一般使用都是public繼承,幾乎很少使用protected/private繼承。也不提倡使用protected/private繼承
對象模型:對象中成員在內存中的佈局形式
繼承方式public:is-----a ( )
可以將子類完全看成是一個基類的對象--------------在類外所以用到基類的對象的位置都可以使用子類的對象代替。!!!!
派生類對象可以賦值給基類對象/基類指針/基類引用。俗稱切片 寓意是把派生類父親那部分切來賦值過去
基類指針或引用指向子類的對象時,只能訪問子類繼承的成員。
繼承中的作用域
- 在繼承體系中基類和派生類都要獨立的作用域
- 子類和父類中有同名成員,子類成員將屏蔽父類對同名成名的直接訪問,這種情況叫做隱藏,也叫重定義。(在子類成員函數中,可以使用基類::基類成員顯示訪問)
- 需要注意的是如果成員函數的隱藏,只需要函數名相同就構成隱藏。
- 注意在實際中在繼承體系裏面最好不要定義同名的成員。
重載:函數在同一作用域,函數名相同,函數參數個數,類型,順序,const volitate不同,與返回值無關
重定義/隱藏:只要子類和父類的函數名相同
派生類的默認成員函數
- 派生類的構造函數必須調用基類的構造函數初始化基類的那一部分成員。如果基類沒有默認構造函數,則必須在派生類構造函數的初始化列表階段顯示調用。
- 派生類的拷貝構造函數必須調用基類的拷貝構造完成基類的拷貝初始化
- 派生類的operator=必須要調用基類的operator=完成基類的複製。
- 派生類的析構函數會在被調用完成後自動調用基類的析構函數清理基類成員。因爲這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。
- 派生類對象初始化先調用基類構造函數再調用派生類構造
- 派生類對象析構清理先調用派生類析構再調基類的析構。
#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
Person(const char* name = "peter")
:_name(name)
{
cout << "Person(const char* name = perter)" << endl;
}
Person(const Person&p)
:_name(p._name)
{
cout << "Person(const Person&p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)
{
_name = p._name;
}
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
private:
string _name;//姓名
};
class Student :public Person
{
public:
Student()
{}
Student(const char* name,int num)
:Person(name)
,_num(num)
{
cout << "Student()" << endl;
}
Student(const Student& s)
:Person(s)
, _num(s._num)
{
cout << "Student(const Student&s)" << endl;
}
Student& operator=(const Student& s)
{
cout << "Student& operator=(const Student& s)" << endl;
if (this != &s)
{
Person::operator=(s);
_num = s._num;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
protected:
int _num;//學號
};
void Test()
{
Student s0;
Student s1("jack", 18);
Student s2(s1);
Student s3("rose", 17);
s1 = s3;
}
int main()
{
Test();
return 0;
}
繼承與友元
友元關係不能被繼承,也就是說基類友元不能訪問子類私有和保護成員
繼承與靜態成員
基類定義了static靜態成員,則整個繼承體系裏面只有一個這樣的成員。無論派生出多少個子類,都只有一個static成員實例。