c++---繼承

在繼承這塊我們從新下面的幾個點去剖析c++中的繼承

  • 繼承的概念和定義
  • 基類和派生類對象賦值轉換
  • 繼承中的作用域
  • 派生類成員的默認成員函數
  • 繼承和友元
  • 繼承與靜態成員
  1. 繼承的概念和定義
  • 繼承的概念

繼承機制是面向對象程序設計使代碼可以複用的最重要的手段,他允許程序員在保持原有類特性的基礎上進行擴展,增加功能,這樣產生的類稱爲派生類。繼承呈現了面向對象程序設計的層次結構,體現了簡單到複雜的認知過程。以前接觸的複用都是函數複用。繼承是類設計層次的複用。
例如Person類,都有一些特定的屬性。比如年齡和姓名。

class Person{
	public:
		void print(){
			cout << "name:"  << _name<<endl;
		}
	protected:
		string _name;
		int _age;
};

比如我們是一個學生去繼承Person類之後我們就可以在屬性中加上學號

class Student : public Person{
protected:
	int _stuid;
};

我們是一個老師的時候就可以在屬性中加上工號

class Teacher : public Person{
protected:
	int _jobid;
};
  • 繼承的定義

下面看到Person是父類,也稱爲基類,Student是子類,也稱爲派生類。
在這裏插入圖片描述

  • 繼承關係和訪問限定符

在這裏插入圖片描述

  • 繼承基類成員訪問方式的變化

在這裏插入圖片描述

a. 基類private成員在派生類中無論以什麼方式繼承都是不可見的。這裏的不可見是指基類的私有成員還是 被繼承到了派生類對象中,但是語法上限制派生類對象不管在類裏面還是類外面都不能去訪問它。
b. 基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能 訪問,就定義爲protected。可以看出保護成員限定符是因繼承纔出現的。
**c.**實際上面的表格我們進行一下總結會發現,基類的私有成員在子類都是不可見。基類的其他成員在子類 的訪問方式 == Min(成員在基類的訪問限定符,繼承方式),public > protected > private。
d. 使用關鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過最好顯示的 寫出繼承方式。
e. 在實際運用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用 protetced/private繼承,因爲protetced/private繼承下來的成員都只能在派生類的類裏面使用,實際中 擴展維護性不強

  1. 基類和派生類對象賦值轉換
  • 派生類對象可以賦值給基類的對象/基類的指針/基類的引用。這裏有個形象的說法就是切片或者說成切割。
  • 基類對象不能賦值給派生類對象
  • 基類的指針可以通過強制雷子那個轉換賦值給派生類,但是必須是基類的指針是指向派生類對象纔是安全的。強制類型轉換講述的很清楚,不知道的小夥伴可以去這裏看看。
    切片
    比如我們上面的Person類和Student類。在父類的屬性中有_name和_age屬性,在子類中多了一個_stuid的屬性,我們將子類中的_stuid切割掉,只剩下上面的兩個屬性。這就叫切片。
    在這裏插入圖片描述
  1. 繼承中的作用域
  • 在繼承體系中基類和派生類都有獨立的作用域。
  • 在子類和父類的同名成員,子類成員將屏蔽對同名成員的直接訪問。這種情況叫隱藏,也叫重定向,想調用父類中的成員的話就直接顯示調用。
  • 如果成員函數構成隱藏的話只需要函數名相同就構成隱藏。
  • 在實際中繼承體系中最好不要定義同名的成員。
#include <iostream>
#include <string>
using namespace std;
class Person{ 
public:
	void Print() {
		cout << "Person" << endl;
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:    
	string _name = "peter"; // 姓名  	  
	int _age = 18;  // 年齡
};
class Student :public Person{
public:
	void Print() {
		cout << "Student" << endl;
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	int _stuid ;
	int _age = 20;
};
int main() {
	Student s;
	s.Print();
	system("pause");
	return 0; 
}


在這裏插入圖片描述
對成員和成員函數都構成了隱藏。

  1. 派生類的默認成員函數

6個默認成員函數,編譯器繪製自動生成一個。

  • 派生類的構造函數必須調用基類的構造函數初始化基類的那一部分成員。如果基類沒有默認的構造函 數,則必須在派生類構造函數的初始化列表階段顯示調用。
  • 派生類的拷貝構造函數必須調用基類的拷貝構造完成基類的拷貝初始化。
  • 派生類的operator=必須要調用基類的operator=完成基類的複製。
  • 派生類的析構函數會在被調用完成後自動調用基類的析構函數清理基類成員。因爲這樣才能保證派生類 對象先清理派生類成員再清理基類成員的順序。
  • 派生類對象初始化先調用基類構造再調派生類構造。
  • 派生類對象析構清理先調用派生類析構再調基類的析構

主要注意我們構造和析構的時機

#include <iostream>
#include <string>
using namespace std;
class Person{ 
public:
	Person(){
		cout << "Person" << endl;
	}
	~Person(){
		cout << "~Person" << endl;
	}

	void Print() {
		cout << "Person" << endl;
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:    
	string _name = "peter"; // 姓名  	  
	int _age = 18;  // 年齡
};
class Student :public Person{
public:
	Student(){
		cout << "Person()" << endl;
	}
	void Print() {
		cout << "Student" << endl;
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
	~Student(){
		cout << "~Student" << endl;
	}
protected:
	int _stuid ;
	int _age = 20;
};
void test(){
	Student s;
}
int main() {
	test();
	system("pause");
	return 0; 
}


在這裏插入圖片描述

  1. 繼承和友元

友元關係並不能被繼承,也就是說基類友元不能訪問子類私有和保護成員。
在這裏插入圖片描述

  1. 繼承與靜態成員

基類定義了static靜態成員,則整個繼承體系裏面只有一個這樣的成員,無論派生出多個子類,都只有一個static成員實例。
看下面的實例

#include <iostream>
#include <string>
using namespace std;
class Person{ 
public:
protected:    
	static int num;
};
int Person::num = 1;
class Student :public Person{
public:
	void Print() {
		cout << &num << endl;
	}
};
class Teacher : public Person{
public:
	void Print(){
		cout << &num << endl;
	}
};

void test(){
	Teacher t;
	Student s;
	s.Print();
	t.Print();
}
int main() {
	test();
	system("pause");
	return 0; 
}


在這裏插入圖片描述
在兩個派生類的分別繼承子類之後再派生類中分別打印出num的地址。結果是一樣的,說明我們的static成員無論有多少個派生類都只會有一個常量num。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章