C++中的基類和派生類構(gòu)造函數(shù)示例詳解
基類的成員函數(shù)可以被繼承,可以通過派生類的對(duì)象訪問,但這僅僅指的是普通的成員函數(shù),類的構(gòu)造函數(shù)不能被繼承。構(gòu)造函數(shù)不能被繼承是有道理的,因?yàn)榧词估^承了,它的名字和派生類的名字也不一樣,不能成為派生類的構(gòu)造函數(shù),當(dāng)然更不能成為普通的成員函數(shù)。

在設(shè)計(jì)派生類時(shí),對(duì)繼承過來的成員變量的初始化工作也要由派生類的構(gòu)造函數(shù)完成,但是大部分基類都有 private 屬性的成員變量,它們在派生類中無法訪問,更不能使用派生類的構(gòu)造函數(shù)來初始化。
這種矛盾在C++繼承中是普遍存在的,解決這個(gè)問題的思路是:在派生類的構(gòu)造函數(shù)中調(diào)用基類的構(gòu)造函數(shù)。
下面的例子展示了如何在派生類的構(gòu)造函數(shù)中調(diào)用基類的構(gòu)造函數(shù):
#include<iostream>
using namespace std;
//基類People
class People{
protected:
char *m_name;
int m_age;
public:
People(char*, int);
};
People::People(char *name, int age): m_name(name), m_age(age){}
//派生類Student
class Student: public People{
private:
float m_score;
public:
Student(char *name, int age, float score);
void display();
};
//People(name, age)就是調(diào)用基類的構(gòu)造函數(shù)
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<"。"<<endl;
}
int main(){
Student stu("小明", 16, 90.5);
stu.display();
return 0;
}運(yùn)行結(jié)果為:小明的年齡是16,成績是90.5。
請(qǐng)注意第 23 行代碼:

Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }People(name, age) 就是調(diào)用基類的構(gòu)造函數(shù),并將 name 和 age 作為實(shí)參傳遞給它, m_score(score) 是派生類的參數(shù)初始化表,它們之間以逗號(hào) , 隔開。也可以將基類構(gòu)造函數(shù)的調(diào)用放在參數(shù)初始化表后面:
Student::Student(char *name, int age, float score): m_score(score), People(name, age){ }但是不管它們的順序如何,派生類構(gòu)造函數(shù)總是先調(diào)用基類構(gòu)造函數(shù)再執(zhí)行其他代碼(包括參數(shù)初始化表以及函數(shù)體中的代碼),總體上看和下面的形式類似:
Student::Student(char *name, int age, float score){
People(name, age);
m_score = score;
}當(dāng)然這段代碼只是為了方便大家理解,實(shí)際上這樣寫是錯(cuò)誤的,因?yàn)榛悩?gòu)造函數(shù)不會(huì)被繼承,不能當(dāng)做普通的成員函數(shù)來調(diào)用。換句話說,只能將基類構(gòu)造函數(shù)的調(diào)用放在函數(shù)頭部,不能放在函數(shù)體中。另外,函數(shù)頭部是對(duì)基類構(gòu)造函數(shù)的調(diào)用,而不是聲明,所以括號(hào)里的參數(shù)是實(shí)參,它們不但可以是派生類構(gòu)造函數(shù)參數(shù)列表中的參數(shù),還可以是局部變量、常量等,例如

Student::Student(char *name, int age, float score): People("小明", 16), m_score(score){ }構(gòu)造函數(shù)的調(diào)用順序
從上面的分析中可以看出,基類構(gòu)造函數(shù)總是被優(yōu)先調(diào)用,這說明創(chuàng)建派生類對(duì)象時(shí),會(huì)先調(diào)用基類構(gòu)造函數(shù),再調(diào)用派生類構(gòu)造函數(shù),如果繼承關(guān)系有好幾層的話,例如:
A --> B --> C
那么創(chuàng)建 C 類對(duì)象時(shí)構(gòu)造函數(shù)的執(zhí)行順序?yàn)椋?/p>
A類構(gòu)造函數(shù) --> B類構(gòu)造函數(shù) --> C類構(gòu)造函數(shù)
構(gòu)造函數(shù)的調(diào)用順序是按照繼承的層次自頂向下、從基類再到派生類的。還有一點(diǎn)要注意,派生類構(gòu)造函數(shù)中只能調(diào)用直接基類的構(gòu)造函數(shù),不能調(diào)用間接基類的。
以上面的 A、B、C 類為例,C 是最終的派生類,B 就是 C 的直接基類,A 就是 C 的間接基類。
C++ 這樣規(guī)定是有道理的,因?yàn)槲覀冊?C 中調(diào)用了 B 的構(gòu)造函數(shù),B 又調(diào)用了 A 的構(gòu)造函數(shù),相當(dāng)于 C 間接地(或者說隱式地)調(diào)用了 A 的構(gòu)造函數(shù),如果再在 C 中顯式地調(diào)用 A 的構(gòu)造函數(shù),那么 A 的構(gòu)造函數(shù)就被調(diào)用了兩次,相應(yīng)地,初始化工作也做了兩次,這不僅是多余的,還會(huì)浪費(fèi)CPU時(shí)間以及內(nèi)存,毫無益處,所以 C++ 禁止在 C 中顯式地調(diào)用 A 的構(gòu)造函數(shù)。
基類構(gòu)造函數(shù)調(diào)用規(guī)則
事實(shí)上,通過派生類創(chuàng)建對(duì)象時(shí)必須要調(diào)用基類的構(gòu)造函數(shù),這是語法規(guī)定。換句話說,定義派生類構(gòu)造函數(shù)時(shí)最好指明基類構(gòu)造函數(shù);如果不指明,就調(diào)用基類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù)的構(gòu)造函數(shù));如果沒有默認(rèn)構(gòu)造函數(shù),那么編譯失敗。請(qǐng)看下面的例子:
#include <iostream>
using namespace std;
//基類People
class People{
public:
People(); //基類默認(rèn)構(gòu)造函數(shù)
People(char *name, int age);
protected:
char *m_name;
int m_age;
};
People::People(): m_name("xxx"), m_age(0){ }
People::People(char *name, int age): m_name(name), m_age(age){}
//派生類Student
class Student: public People{
public:
Student();
Student(char*, int, float);
public:
void display();
private:
float m_score;
};
Student::Student(): m_score(0.0){ } //派生類默認(rèn)構(gòu)造函數(shù)
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<"。"<<endl;
}
int main(){
Student stu1;
stu1.display();
Student stu2("小明", 16, 90.5);
stu2.display();
return 0;
}運(yùn)行結(jié)果:xxx的年齡是0,成績是0。
小明的年齡是16,成績是90.5。
創(chuàng)建對(duì)象 stu1 時(shí),執(zhí)行派生類的構(gòu)造函數(shù) Student::Student() ,它并沒有指明要調(diào)用基類的哪一個(gè)構(gòu)造函數(shù),從運(yùn)行結(jié)果可以很明顯地看出來,系統(tǒng)默認(rèn)調(diào)用了不帶參數(shù)的構(gòu)造函數(shù),也就是 People::People() 。
創(chuàng)建對(duì)象 stu2 時(shí),執(zhí)行派生類的構(gòu)造函數(shù) Student::Student(char *name, int age, float score) ,它指明了基類的構(gòu)造函數(shù)。
在第 27 行代碼中,如果將 People(name, age) 去掉,也會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù),第 37 行的輸出結(jié)果將變?yōu)椋簒xx的年齡是0,成績是90.5。
如果將基類 People 中不帶參數(shù)的構(gòu)造函數(shù)刪除,那么會(huì)發(fā)生編譯錯(cuò)誤,因?yàn)閯?chuàng)建對(duì)象 stu1 時(shí)需要調(diào)用 People 類的默認(rèn)構(gòu)造函數(shù), 而 People 類中已經(jīng)顯式定義了構(gòu)造函數(shù),編譯器不會(huì)再生成默認(rèn)的構(gòu)造函數(shù)。
到此這篇關(guān)于C++的基類和派生類構(gòu)造函數(shù)的文章就介紹到這了,更多相關(guān)C++基類構(gòu)造函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++教程之a(chǎn)rray數(shù)組使用示例詳解
這篇文章主要為大家介紹了C++教程之a(chǎn)rray數(shù)組使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Visual Studio2022+QT6創(chuàng)建桌面應(yīng)用實(shí)現(xiàn)
本文主要介紹了Visual Studio2022+QT6創(chuàng)建桌面應(yīng)用實(shí)現(xiàn),文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
帶你了解C++的動(dòng)態(tài)內(nèi)存分配
今天小編就為大家分享一篇關(guān)于關(guān)于C++動(dòng)態(tài)分配內(nèi)存的介紹,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2021-08-08
C語言/C++中如何產(chǎn)生隨機(jī)數(shù)
這里要用到的是rand()函數(shù), srand()函數(shù),和time()函數(shù)。需要說明的是,iostream頭文件中就有srand函數(shù)的定義,不需要再額外引入stdlib.h;而使用time()函數(shù)需要引入ctime頭文件2013-10-10
高效實(shí)現(xiàn)整型數(shù)字轉(zhuǎn)字符串int2str的方法
下面小編就為大家?guī)硪黄咝?shí)現(xiàn)整型數(shù)字轉(zhuǎn)字符串int2str的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03
10行C++代碼實(shí)現(xiàn)高性能HTTP服務(wù)
這篇文章主要介紹了10行C++代碼如何實(shí)現(xiàn)高性能HTTP服務(wù),幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下2021-04-04

