c 學習筆記 類繼承

2021-07-04 18:30:18 字數 3070 閱讀 3413

現在有乙個記錄身份id的類:

#ifndef head_h_

#define head_h_

#include #include using namespace std;

class idcard

};#endif

實現部分:

#include "head.h"

idcard::idcard(const string n, const int i) :name(n), id(i)

{}void idcard::show()const

例如現在派生乙個student類:

...class student :public idcard

}

實現部分:

...student::student(const string n, const int i, const string g, const string t) :idcard(n, i), grade(g), teacher(t)

{} student::student(const idcard &c, const string g, const string t) : idcard(c), grade(g), teacher(t)

{} ostream &operator<<(ostream &os, const student &s)

void student::show()const

p->show();

在這裡你可能希望p能夠根據指向的型別來確定show方法,但是在這裡永遠只會使用基類的show。

有什麼方法可以實現?使用虛函式(虛方法)  使用關鍵字virtual

virtual 返回值型別 函式名(形參列表)

//函式體

如果使用關鍵字virtual後,該方法被宣告為虛,這樣會程式將根據引用或指標指向的物件的型別來選擇方法。

改變一下之前定義的兩個show方法

virtual void show()const; //idcard

virtual void show()const; //student

virtual ~idcard(){};

當使用者選擇1時使用的是idcard的show,顯示名字和id

當使用者選擇2時使用的是student的show,顯示名字、id和score

當基類定義虛函式時,例如上面的show(),在派生類裡的同名、引數列表相同的函式也會自動變成虛函式,不管有沒有加virtual關鍵字。

虛函式要注意的一些:

在基類方法的宣告中使用關鍵字virtual可以使該方法在基類以及所有的派生類中是虛的(包括從派生類派生出來的類)。

在使用指標或引用呼叫虛函式時,程式將使用物件型別對應的虛函式,而不是使用指標或引用的型別的虛函式,這稱為動態聯編,這樣基類指標可以指向派生類物件並呼叫派生類物件的虛函式。

基類應該把需要在派生類中重新定義的方法宣告為虛(函式名、引數列表都相同)。

建構函式不能為虛,因為建構函式只對應該類,構造該類,派生類不繼承基類的建構函式。

析構函式應當為虛的,除非該類不用做基類,例如:idcard *p=char student; delete p; 這時如果析構函式不為虛的,這只會呼叫基類的析構函式,而派生類因為沒有呼叫,所以派生類部分沒有釋放記憶體。

當析構函式為虛的時候delete p;將呼叫指向的物件的型別的析構函式,而派生類的析構函式會呼叫基類的析構函式。

友元不能是虛函式,因為友元根本就不是類成員,而且只有類成員才能使虛函式。

如果派生類中沒有重新定義基類中有的函式,如show,將使用該函式的基類版本,因為只有基類有這個方法,如果派生類中定義了與基類引數列表不同的虛函式(函式名相同),如是show(int n),而不是show();

這將會隱藏基類的版本:

student stu;

stu.show(); //無效的

stu.show(3); //有效的

如果重新定義繼承的方法,應該確保與原來的函式原型完全相同,但是如果返回的型別是基類引用或指標,則可以修改為指向派生類的引用或指標,這種特性稱為返回型別協變,因為允許返回型別隨類的型別的變化而改變:

class a

;class b : public a

;

這種方法只適用於返回值,不適用於引數。

如果基類的宣告被過載了,則需要在派生類中重新定義所有的基類版本:

class a

class b : public a

再來看看繼承與動態記憶體分配的一些問題:

class a

class b : public a

類a採用new分配記憶體給label。

現在有幾個問題:

派生類b需要顯式的析構函式、複製建構函式和賦值運算子麼?

首先不需要析構函式,因為陣列可以通過預設的析構函式來釋放,然後預設的析構函式會自動呼叫基類的析構函式,所以可以完全清理。

然後複製建構函式也不需要,預設的複製建構函式能實現把陣列複製的功能,然後基類部分會自己呼叫基類的複製建構函式。

賦值運算子也是如此,預設的賦值運算子能複製陣列,也會呼叫基類的賦值運算子。

那麼現在類b來改變一下:

class b : public a

然後也是這幾個問題:派生類b需要顯式的析構函式、複製建構函式和賦值運算子麼?

首先需要定義析構函式,因為預設的析構函式只會清理type指標所佔的記憶體,不會清理指向的記憶體,所以需要定義乙個使用delete的析構函式。

然後也需要複製建構函式,預設的複製建構函式賦值的是值,也就是說會把type指標儲存的記憶體位址複製,這回造成嚴重的後果,所以需要定義乙個實現釋放舊記憶體、分配新記憶體和靠背陣列的複製建構函式。

複製運算子和複製建構函式差不多,也是只會複製位址,所以需要定義乙個實現釋放舊記憶體、分配新記憶體和靠背陣列的複製運算子。

C 學習筆記 類的繼承(一)

由c 構成的抽象世界存在is a kind of 的關係 例如 在c 裡,由繼承的語法來表示is lind of的關係 class file class videofile public file 語法 class b public a 表示類b繼承於類a,把a稱為父類 基類 把b稱為子類 派生類 ...

c 個人學習筆記 類繼承

面對物件過程程式設計的主要目的之一是提供可重用的 塊。當專案十分龐大時,對已通過測試的 進行重用比重新編寫 更能提供效率,節省時間。c 通過擴充套件和修改類來提高 的重用性,這種方法叫類繼承。從已有的類 基類 派生出新的類 派生類 派生類繼承了基類的所有特性 成員變數 方法等 並且還可以在此基礎上新...

C 學習筆記 類的繼承(派生類)

1 引言 馬克思說 世界是聯絡的,哈哈。搞笑了。進入正題,現實中的乙個概念不是鼓勵存在的,總是與一些相關的概念存在的,他們之間總是相互聯絡的,而且他們之間會表現出一種層次的關係,共性 層次 我們就引出了派生類的概念。2 派生類 1 employee與manager struct employee s...