C 基類和派生類的建構函式

2021-10-23 15:49:20 字數 2762 閱讀 7057

前面我們說基類的成員函式可以被繼承,可以通過派生類的物件訪問,但這僅僅指的是普通的成員函式,類的建構函式不能被繼承。建構函式不能被繼承是有道理的,因為即使繼承了,它的名字和派生類的名字也不一樣,不能成為派生類的建構函式,當然更不能成為普通的成員函式。

在設計派生類時,對繼承過來的成員變數的初始化工作也要由派生類的建構函式完成,但是大部分基類都有 private 屬性的成員變數,它們在派生類中無法訪問,更不能使用派生類的建構函式來初始化。

這種矛盾在c++繼承中是普遍存在的,解決這個問題的思路是:在派生類的建構函式中呼叫基類的建構函式。

下面的例子展示了如何在派生類的建構函式中呼叫基類的建構函式:

#include

using namespace std;

//基類people

class people;

people::people(char *name, int age): m_name(name), m_age(age){}

//派生類student

class student: public people;

//people(name, age)就是呼叫基類的建構函式

student::student(char *name, int age, float score): people(name, age), m_score(score)

void student::display()

people(name, age)就是呼叫基類的建構函式,並將 name 和 age 作為實參傳遞給它,m_score(score)是派生類的引數初始化表,它們之間以逗號,隔開。

也可以將基類建構函式的呼叫放在引數初始化表後面:

student::student(char *name, int age, float score): m_score(score), people(name, age)

但是不管它們的順序如何,派生類建構函式總是先呼叫基類建構函式再執行其他**(包括引數初始化表以及函式體中的**),總體上看和下面的形式類似:

student::student(char *name, int age, float score)

當然這段**只是為了方便大家理解,實際上這樣寫是錯誤的,因為基類建構函式不會被繼承,不能當做普通的成員函式來呼叫。換句話說,只能將基類建構函式的呼叫放在函式頭部,不能放在函式體中。

另外,函式頭部是對基類建構函式的呼叫,而不是宣告,所以括號裡的引數是實參,它們不但可以是派生類構造函式引數列表中的引數,還可以是區域性變數、常量等,例如:

student::student(char *name, int age, float score): people(「小明」, 16), m_score(score)

建構函式的呼叫順序

從上面的分析中可以看出,基類建構函式總是被優先呼叫,這說明建立派生類物件時,會先呼叫基類建構函式,再呼叫派生類建構函式,如果繼承關係有好幾層的話,例如:

a --> b --> c

那麼建立 c 類物件時建構函式的執行順序為:

a類建構函式 --> b類建構函式 --> c類建構函式

建構函式的呼叫順序是按照繼承的層次自頂向下、從基類再到派生類的。

還有一點要注意,派生類建構函式中只能呼叫直接基類的建構函式,不能呼叫間接基類的。以上面的 a、b、c 類為例,c 是最終的派生類,b 就是 c 的直接基類,a 就是 c 的間接基類。

c++ 這樣規定是有道理的,因為我們在 c 中呼叫了 b 的建構函式,b 又呼叫了 a 的建構函式,相當於 c 間接地(或者說隱式地)呼叫了 a 的建構函式,如果再在 c 中顯式地呼叫 a 的建構函式,那麼 a 的建構函式就被呼叫了兩次,相應地,初始化工作也做了兩次,這不僅是多餘的,還會浪費cpu時間以及記憶體,毫無益處,所以 c++ 禁止在 c 中顯式地呼叫 a 的建構函式。

基類構造函式呼叫規則

事實上,通過派生類建立物件時必須要呼叫基類的建構函式,這是語法規定。換句話說,定義派生類建構函式時最好指明基類建構函式;如果不指明,就呼叫基類的預設建構函式(不帶引數的建構函式);如果沒有預設建構函式,那麼編譯失敗。請看下面的例子:

純文字複製

#include

using namespace std;

//基類people

class people;

people::people(): m_name(「***」), m_age(0)

people::people(char name, int age): m_name(name), m_age(age){}

//派生類student

class student: public people;

student::student(): m_score(0.0) //派生類預設建構函式

student::student(char *name, int age, float score): people(name, age), m_score(score)

void student::display(){

cout《建立物件 stu1 時,執行派生類的建構函式student::student(),它並沒有指明要呼叫基類的哪乙個建構函式,從執行結果可以很明顯地看出來,系統預設呼叫了不帶引數的建構函式,也就是people::people()。

建立物件 stu2 時,執行派生類的建構函式student::student(char *name, int age, float score),它指明了基類的建構函式。

在第 27 行**中,如果將people(name, age)去掉,也會呼叫預設建構函式,第 37 行的輸出結果將變為:

***的年齡是0,成績是90.5。

C 基類和派生類的建構函式(詳解)

基類的成員函式可以被繼承,可以通過派生類的物件訪問,但這僅僅指的是普通的成員函式,類的建構函式不能被繼承。建構函式不能被繼承是有道理的,因為即使繼承了,它的名字和派生類的名字也不一樣,不能成為派生類的建構函式,當然更不能成為普通的成員函式。在設計派生類時,對繼承過來的成員變數的初始化工作也要由派生類...

基類與派生類的建構函式

一 預設建構函式的呼叫關係 通過下面的例子,我們來看一下基類與派生的建構函式的呼叫順序。建立時先基類後派生類。銷毀時先派生類後基類。include include using namespace std class cbase cbase class cderive public cbase cde...

c ,派生類無法呼叫基類建構函式

include include using namespace std class undergraduate void showinfo private char id 10 char name 10 char major 10 class graduate public undergraduat...