繼承(多態和虛析構函數)

派生類不能直接訪問基類的私有成員,必須通過基類方法進行訪問。創建派生類對象時,首先創建基類對象。也就是說基類對象在程序進入派生類構造函數之前被創建。C++使用成員初始化列表來完成。派生類構造函數初始化基類私有成員,採用成員初始化列表。
總結:
首先,若基類函數需要被派生類重定義,則需要將其在基類聲明爲虛函數。
虛函數必須完全一致,否則派生類將重定義函數,隱藏基類虛函數。返回值除外
析構函數須使用虛析構函數,防止因指針或引用類型導致析構錯誤對象。
虛函數採用動態聯編,不同位置虛函數存在不同地址,每個對象包含不同函數地址。

Class_name::Class_name(int a,int b, int c):Base_class(a,b) {    }

派生類構造函數要點:

  1. 首先創建基類對象
  2. 派生類構造函數應通過成員初始化列表將基類信息傳遞給基類構造函數
  3. 派生類構造函數應初始化派生類新增的成員變量
    注意: 成員初始化列表只能用於構造函數

派生類和基類的關係

1.1 派生類可使用基類的方法(非私有)

基類指針可以在不進行顯示類型轉換情況下指向派生類對象;基類引用可在不進行顯示類型轉換的情況下引用派生類對象。同樣也可以將派生類對象賦給基類對象。
基類指針或引用只能用於調用基類方法,因此不能使用其調用派生類方法。 通常要求引用和指針類型與賦給的類型匹配,但這一規則對繼承來說是例外。不可以將基類對象和地址賦給派生類引用和指針。

1.2 多態公有繼承

概念: 同一個方法在派生類和基類中的行爲是不同的,那麼方法的行爲應取決於調用該方法的對象,稱爲多態。
方法:

  1. 派生類中重新定義基類的方法
  2. 使用虛函數
    要點: 若要在派生類重新定義基類方法,通常將基類方法聲明 (定義不需要)爲虛函數。爲基類聲明一個虛析構函數也是一種慣例。

重定義基類方法

  1. 在基類和派生類中分別定義一個同名函數,則根據對象類型來分別調用相應的函數。
class Student {
	string name;
	int age;
public:
	Student(string a,int b):name(a),age(b){}
	void Print() {
		cout << "調用Student: "<<name << endl;
	}
};
class Grade :public Student{
	int grade;
public:
	Grade(int a, string name, int b) :Student(name, b) {
		grade = a;
	}
	void Print() {
		cout << "調用grade: " << grade << endl;
	}

};

可見函數Print()在基類和派生類分別定義了,若對象調用 如下:

Student S("liming", 13);
	S.Print();
	Grade G1(10, "lama", 20);
	G1.Print();

結果爲:

調用Student: liming
調用grade: 10
  1. 方法通過引用或者指針而不是對象調用的,沒有使用virtual 定義,則根據引用類型或指針類型選擇方法。
    調用如下:
Student S("liming", 13);
	S.Print();
	Student *S1;
	Grade G1(10, "lama", 20);
	Student &S2 = G1;
	S2.Print();
	S1 = &G1;
	S1->Print();
	G1.Print();

結果爲:

調用Student: liming
調用Student: lama
調用Student: lama
調用grade: 10
  1. 如果使用virtual 程序將根據引用或指針指向的對象類型來選擇方法。
    將方法定義設置爲:
virtual void Print() {
		cout << "調用Student: "<<name << endl;
	}

Student S("liming", 13);
	S.Print();
	Student *S1;
	Grade G1(10, "lama", 20);
	Student &S2 = G1;
	S2.Print();
	S1 = &G1;
	S1->Print();
	G1.Print();

結果爲:

調用Student: liming
調用grade: 10
調用grade: 10
調用grade: 10

虛析構函數的作用

在使用newdelete的對象中,如果析構函數不是虛的,則只調用對應於指針類型的析構函數。


	Student *S1 = new Grade(12, "ll", 17);
	delete S1;

結果爲:

調用Student構造函數:
調用grade構造函數:
調用student析構函數

由此可見,並沒有調用派生類的析構函數。
若將基類析構函數設爲vritual,則結果如下:

調用Student構造函數:
調用grade構造函數:
調用Grade析構函數
調用student析構函數

所以應將析構函數設爲虛析構函數。

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