深刻解析C++中派生類的結構函數。本站提示廣大學習愛好者:(深刻解析C++中派生類的結構函數)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++中派生類的結構函數正文
基類的結構函數不克不及被繼續,在聲明派生類時,對繼續過去的成員變量的初始化任務也要由派生類的結構函數來完成。所以在設計派生類的結構函數時,不只要斟酌派生類新增的成員變量,還要斟酌基類的成員變量,要讓它們都被初始化。
處理這個成績的思緒是:在履行派生類的結構函數時,挪用基類的結構函數。
上面的例子展現了若何在派生類的結構函數中挪用基類的結構函數。
#include<iostream> using namespace std; //基類 class People{ protected: char *name; int age; public: People(char*, int); }; People::People(char *name, int age): name(name), age(age){} //派生類 class Student: public People{ private: float score; public: Student(char*, int, float); void display(); }; //挪用了基類的結構函數 Student::Student(char *name, int age, float score): People(name, age){ this->score = score; } void Student::display(){ cout<<name<<"的年紀是"<<age<<",成就是"<<score<<endl; } int main(){ Student stu("小明", 16, 90.5); stu.display(); return 0; }
運轉成果為:
小明的年紀是16,成就是90.5
請留意代碼第23行:
Student::Student(char *name, int age, float score): People(name, age)
這是派生類 Student 的結構函數的寫法。冒號後面是派生類結構函數的頭部,這和我們之前引見的結構函數的情勢一樣,但它的形參列表包含了初始化基類和派生類的成員變量所需的數據;冒號前面是對基類結構函數的挪用,這和通俗結構函數的參數初始化表異常相似。
現實上,你可以將對基類結構函數的挪用和參數初始化表放在一路,以下所示:
Student::Student(char *name, int age, float score): People(name, age), score(score){}
基類結構函數和初始化表用逗號離隔。
須要留意的是:冒號前面是對基類結構函數的挪用,而不是聲明,所以括號裡的參數是實參,它們不只可所以派生類結構函數總參數表中的參數,還可所以部分變量、常量等。以下所示:
Student::Student(char *name, int age, float score): People("李磊", 20)
基類結構函數挪用規矩
現實上,經由過程派生類創立對象時必需要挪用基類的結構函數,這是語律例定。也就是說,界說派生類結構函數時最好指明基類結構函數;假如不指明,就挪用基類的默許結構函數(不帶參數的結構函數);假如沒有默許結構函數,那末編譯掉敗。
請看上面的例子:
#include<iostream> using namespace std; //基類 class People{ protected: char *name; int age; public: People(); People(char*, int); }; People::People(){ this->name = "xxx"; this->age = 0; } People::People(char *name, int age): name(name), age(age){} //派生類 class Student: public People{ private: float score; public: Student(); Student(char*, int, float); void display(); }; Student::Student(){ this->score = 0.0; } Student::Student(char *name, int age, float score): People(name, age){ this->score = score; } void Student::display(){ cout<<name<<"的年紀是"<<age<<",成就是"<<score<<endl; } int main(){ Student stu1; stu1.display(); Student stu2("小明", 16, 90.5); stu2.display(); return 0; }
運轉成果:
xxx的年紀是0,成就是0 小明的年紀是16,成就是90.5
創立對象 stu1 時,履行派生類的結構函數 Student::Student(),它並沒有指明要挪用基類的哪個結構函數,從運轉成果可以很顯著地看出來,體系默許挪用了不帶參數的結構函數,也就是 People::People()。
創立對象 stu2 時,履行派生類的結構函數 Student::Student(char *name, int age, float score),它指清楚明了基類的結構函數。
在第31行代碼中,假如將 People(name, age) 去失落,也會挪用默許結構函數,stu2.display() 的輸入成果將變成:
xxx的年紀是0,成就是90.5
假如將基類 People 中不帶參數的結構函數刪除,那末會產生編譯毛病,由於創立對象 stu1 時沒有挪用基類結構函數。
總結:假如基類有默許結構函數,那末在派生類結構函數中可以不指明,體系會默許挪用;假如沒有,那末必需要指明,不然體系不曉得若何挪用基類的結構函數。
結構函數的挪用次序
為了弄清這個成績,我們無妨先來看一個例子:
#include<iostream> using namespace std; //基類 class People{ protected: char *name; int age; public: People(); People(char*, int); }; People::People(): name("xxx"), age(0){ cout<<"PeoPle::People()"<<endl; } People::People(char *name, int age): name(name), age(age){ cout<<"PeoPle::People(char *, int)"<<endl; } //派生類 class Student: public People{ private: float score; public: Student(); Student(char*, int, float); }; Student::Student(): score(0.0){ cout<<"Student::Student()"<<endl; } Student::Student(char *name, int age, float score): People(name, age), score(score){ cout<<"Student::Student(char*, int, float)"<<endl; } int main(){ Student stu1; cout<<"--------------------"<<endl; Student stu2("小明", 16, 90.5); return 0; }
運轉成果:
PeoPle::People() Student::Student() -------------------- PeoPle::People(char *, int) Student::Student(char*, int, float)
從運轉成果可以清晰地看到,當創立派生類對象時,先挪用基類結構函數,再挪用派生類結構函數。假如繼續關系有好幾層的話,例如:
A --> B --> C
那末則創立C類對象時,結構函數的履行次序為:
A類結構函數 --> B類結構函數 --> C類結構函數
結構函數的挪用次序是依照繼續的條理自頂向下、從基類再到派生類的。
C++有子對象的派生類的結構函數
類的數據成員不只可所以尺度型(如int、char)或體系供給的類型(如string),還可以包括類對象,如可以在聲明一個類時包括如許的數據成員:
Student s1; //Student是已聲明的類名,s1是Student類的對象
這時候,s1就是類對象中的內嵌對象,稱為子對象(subobject),即對象中的對象。
那末,在對數據成員初始化時如何對子對象初始化呢?請細心剖析上面法式,特殊留意派生類結構函數的寫法。
[例] 包括子對象的派生類的結構函數。為了簡化法式以易於浏覽,這裡設基類Student的數據成員只要兩個,即num和name。
#include <iostream> #include <string> using namespace std; class Student//聲明基類 { public: //公用部門 Student(int n, string nam ) //基類結構函數,與例11.5雷同 { num=n; name=nam; } void display( ) //成員函數,輸入基類數據成員 { cout<<"num:"<<num<<endl<<"name:"<<name<<endl; } protected: //掩護部門 int num; string name; }; class Student1: public Student //聲明公用派生類Student1 { public: Student1(int n, string nam,int n1, string nam1,int a, string ad):Student(n,nam),monitor(n1,nam1) //派生類結構函數 { age=a; addr=ad; } void show( ) { cout<<"This student is:"<<endl; display(); //輸入num和name cout<<"age: "<<age<<endl; //輸入age cout<<"address: "<<addr<<endl<<endl; //輸入addr } void show_monitor( ) //成員函數,輸入子對象 { cout<<endl<<"Class monitor is:"<<endl; monitor.display( ); //挪用基類成員函數 } private: //派生類的公有數據 Student monitor; //界說子對象(班長) int age; string addr; }; int main( ) { Student1 stud1(10010,"Wang-li",10001,"Li-sun",19,"115 Beijing Road,Shanghai"); stud1.show( ); //輸入先生的數據 stud1.show_monitor(); //輸入子對象的數據 return 0; }
運轉時的輸入以下:
This student is: num: 10010 name: Wang-li age: 19 address:115 Beijing Road,Shanghai Class monitor is: num:10001 name:Li-sun
請留意在派生類Student1中有一個數據成員:
Student monitor; //界說子對象 monitor(班長)
“班長”的類型不是簡略類型(如int、char、float等),它是Student類的對象。我們曉得, 應該在樹立對象時對它的數據成員初始化。那末如何對子對象初始化呢?明顯不克不及在聲明派生類時對它初始化(如Student monitor(10001, "Li-fun");),由於類是籠統類型,只是一個模子,是不克不及有詳細的數據的,並且每個派生類對象的子對象普通是不雷同的(例如先生A、B、C的班長是A,而先生D、E、F的班長是F)。是以子對象的初始化是在樹立派生類時經由過程挪用派生類結構函數來完成的。
派生類結構函數的義務應當包含3個部門:
法式中派生類結構函數首部以下:
Student1(int n, string nam,int n1, string nam1,int a, string ad): Student(n,nam),monitor(n1,nam1)
在下面的結構函數中有6個形參,前兩個作為基類結構函數的參數,第3、第4個作為子對象結構函數的參數,第5、第6個是用作派生類數據成員初始化的。
歸結起來,界說派生類結構函數的普通情勢為: 派生類結構函數名(總參數表列): 基類結構函數名(參數表列), 子對象名(參數表列)
{
派生類中新增數成員據成員初始化語句
}
履行派生類結構函數的次序是:
挪用基類結構函數,對基類數據成員初始化;
挪用子對象結構函數,對子對象數據成員初始化;
再履行派生類結構函數自己,對派生類數據成員初始化。
派生類結構函數的總參數表列中的參數,應該包含基類結構函數和子對象的參數表列中的參數。基類結構函數和子對象的順序可所以隨意率性的,如下面的派生類結構函數首部可以寫成
Student1(int n, string nam,int n1, string nam1,int a, string ad): monitor(n1,nam1),Student(n,nam)
編譯體系是依據雷同的參數名(而不是依據參數的次序)來確立它們的傳遞關系的。然則習氣上普通先寫基類結構函數。
假如有多個子對象,派生類結構函數的寫法依此類推,應列出每個子對象名及其參數表列。