?上篇模板文章:24. C++模板 2 (非類型模板參數,模板的特化與模板的分離編譯)-CSDN博客
?本篇代碼:c++學習 · 橘子真甜/c++-learning-of-yzc - 碼云 - 開源中國 (gitee.com)
?標?是比較重要的部分
目錄
一. 繼承的基礎使用
1.1 繼承的格式
1.2 代碼舉例
1.3 派生類訪問基類成員的變化?
二. 繼承的復制兼容規則??
?三. 繼承中的作用域
3.1 基類可以訪問父類成員函數
3.2 基類與派生類的重定義
一. 繼承的基礎使用
? ? ? ? 繼承的面向對象程序設計提高代碼復用的重要手段,它允許我們在保持原有類的成員的基礎上對這個類進行拓展。之前我們大多都是函數的復用,繼承是類的復用。
? ? ? ? 被繼承的類稱為基類(父類),繼承基類的類稱為派生類(子類)。
? ? ? ??比如我們有一個person類,而學生,職工,教師等類都有著person類的屬性(年齡,性別,電話,身份證等)而學生有自己特有的學號,教師職工有自己的工號。
????????此時我們就能通過繼承讓學生,教師,職工類獲取person的成員,還能重新定義自己特有的成員。
1.1 繼承的格式
class Person
{};class Student :public Person
{};
在新定義的類后面使用一個 : 后面依次接 繼承方式 基類
?
1.2 代碼舉例
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "張三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年齡:" << _age << endl;}
private:size_t _age;string _name;
};class Student :public Person
{
private:string _stuid;
};class Teacher :public Person
{
private:string _tcid;
};int main()
{Person p1;p1.print();Student st1;st1.print();Teacher tc1;tc1.print();return 0;
}
上面代碼中我們定義一個person類,在定義學生和教師類來繼承person?。
我們都調用print函數,運行結果如下:
可見:學生類和教師類(派生類)都能夠繼承person類(基類)的姓名,年齡和print函數
1.3 派生類訪問基類成員的變化?
? ? ? ? 繼承的方式有三種,public,protected,private。不同的繼承方式,子類訪問父類有限定。
類成員/繼承方式 | public繼承 | protected繼承 | private繼承 |
基類public成員 | 派生類public成員 | 派生類protected成員 | 派生類private成員 |
基類protected成員 | 派生類protected成員 | 派生類protected成員 | 派生類private成員 |
基類private成員 | 派生類不可訪問 | 派生類不可訪問 | 派生類不可訪問 |
?根據上述表格,我們可以有以下總結
1 基類的private成員在派生類中不可見。即這個成員被派生類繼承,但是在派生類的類內類外都無法訪問基類的private成員
2 protected繼承就是為了解決基類private成員無法在派生類訪問的問題(即如果我們想要在派生類訪問基類的私有成員,在基類中將其定義為protected成員即可)
3 實際上,為了提高代碼的復用和拓展。我們一般都使用public繼承
4 class定義類的默認繼承方式是private,struct定義類的默認繼承方式是public。不過我們在使用中一般都會顯示定義類的繼承方式。
?
?若是保護成員,在派生類中可以訪問
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "張三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年齡:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
public:void show(){cout << "姓名:" << _name << " 年齡:" << _age << endl;}
private:string _stuid;
};int main()
{Person p1;p1.print();Student st1;st1.show();return 0;
}
我們在Student類中定義一個show函數來訪問基類的保護成員
二. 繼承的復制兼容規則??
派生類的對象可以賦值給 基類,基類的指針,基類的引用(稱為切片,切割)
基類的對象不能賦值給派生類
基類的指針在特定情況下可以強制轉化為派生類的指針
代碼舉例:
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "張三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年齡:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
public:void set(int age, const string& name,int stuid){_age = age;_name = name;_stuid = stuid;}void show(){cout << "姓名:" << _name << " 年齡:" << _age << " ID:" << _stuid << endl;}
private:string _stuid;
};int main()
{Student st1;st1.set(50, "李四", 123456);st1.print();Student st2;Person p1 = st1; //直接賦值p1.print();Person* p2 = &st2; //基類指針p2->print();Person& p3 = st2; //基類引用p3.print();return 0;
}
運行結果如下:
?若是將基類賦值給派生類就會報錯
???????
?三. 繼承中的作用域
1 在繼承中,基類和派生類有自己獨立的作用域。對于派生類來說,調用成員的時候會現在自己的類中尋找,如果自己的類中沒有定義,再去基類中尋找成員
2?基類和其派生類有相同名稱的成員,派生類會隱藏基類的成員。這兩個成員構成重定義。
3 重定義不是重載。雖然兩個成員名稱相同,但是它兩的作用域不一樣,不是重載
3.1 基類可以訪問父類成員函數
舉例代碼如下:基類沒有print函數,會去父類尋找并調用print函數
#include <iostream>
using namespace std;class Person
{
public:Person(int age = 18, const string& name = "張三"):_age(age), _name(name){};void print(){cout << "姓名:" << _name << " 年齡:" << _age << endl;}
protected:size_t _age;string _name;
};class Student :public Person
{
private:string _stuid;
};int main()
{Student st1;st1.print();return 0;
}
測試結果如下:
?
3.2 基類與派生類的重定義
如果父子類有重定義,子類無法直接調用父類的成員
?
調用自己的成員
#include <iostream>
using namespace std;class A
{
public:void f() { cout << "hello world!" << endl; }
};class B :public A
{
public:void f(int i) { cout << "hello world!" << i << endl; }
};int main()
{A a;B b;a.f();b.f(10);return 0;
}
?如果父子類構成重定義,子類想要訪問父類同名成員,需要指定作用域