析構函數(destructor)與構造函數相反,當對象脫離其作用域時(例如對象所在的函數已調用完畢),系統自動執行析構函數。析構函數往往用來做清理善后的工作(例如在建立對象時用new開辟了一片內存空間,應在退出前在析構函數中用delete釋放)。 析構函數名也應與類名相同,只是在函數名前面加一個波浪符~ ,例如~stud(),以區別于構造函數。它不能帶任何參數,也沒有返回值(包括void類型)。只能有一個析構函數,不能重載。如果用戶沒有編寫析構函數,編譯系統會自動生成一個缺省的析構函數,它也不進行任何操作。所以許多簡單的類中沒有用顯式的析構函數。
/*包含構造函數和析構函數的c++程序*/#include<string.h>#include<iostream.h>class stud{ PRivate: int num; char name[]; char sex; public: stud(int n,char nam[],char s) { n=num; strcpy(name,nam); sex=s; } ~stud() {} void display() { cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }};void main(){stud stud1(10010,"Wangjun",'M'),stud2(10011,"jianglin",'F')stud1.display();stud2.display();}現在把類的聲明放在main函數之前,它的作用域是全局的。這樣做可以使main函數更簡練一些。在main函數中定義了兩個對象并且給出了初值。然后輸出兩個學生的數據。 本程序中,成員函數是在類中定義的,如果成員函數的數目很多以及函數的長度很長,類的聲明就會占很大的篇幅,不利于閱讀程序。可以在類的外面定義成員函數,而在類中只用函數的原型作聲明。
//在類的外面定義成員函數#include<string.h>#include<iostream.h>/*如果你用#include<iostream.h>就不需寫這句話(舊標準)。但是如果你用#include<iostream>就必須要寫using namespace std。*/class stud{ private: int num; char name[10];//錯寫成char name; char sex;public: stud(int n,char nam[],char s); ~stud(); void display();};stud::stud(int n,char nam[],char s){ num=n; strcpy(name,nam); sex=s;}stud::~stud(){}void stud::display()//少寫了void{ cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl;}void main(){ stud stud1(10010,"Wangjun",'M'),stud2(10011,"chenglin",'F'); stud1.display(); stud2.display();}在類聲明的外部定義函數,必須指定類名,函數首行的形式為 函數類型 類名::函數名(形參表列)
面向對象技術強調軟件的可重用性。在c++中可重用性是通過繼承這一機制來實現的。因此,繼承是C++的一重要組成部分。 前面介紹了類,一個類中包含了若干數據成員和成員函數。每個類的數據成員和成員函數是不相同的。但是有的時候兩個類的內容基本相同或有一部分相同。 例如前面聲明了學生基本數據的類stud;
class stud{ private: int num; char name; char sex; public: void display() { cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }}如果學校的某個部門除了需要用到學號、姓名、性別以外,還需要用到年齡、地址等信息。當然可以重新聲明另外一類:
class stud1{ private: int num; char name; char sex; int age; char addr[20]; public: void display() { cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; cout<<"age:"<<age<<endl; cout<<"addr:"<<addr<<endl; }};可以看到相當一部分是原來已有的。很少人自然會想到能否利用原有聲明的類作為基礎,再加上新的內容即可,以減少重復的工作量。C++提供的繼承機制就是解決這個問題。
在c++中所謂的繼承就是在一個已存在的類的基礎上建立一個新的類,已存在的類稱為基類或父類;新建立的類稱為派生類或子類,派生類繼承了基類的所以數據成員和成員函數,并增加新的成員。
先通過一個例子說明怎樣通過繼承來建立派生類 假設已經聲明了一個基類stud,在此基礎上聲明一個派生類student:
class student:public stud{ private: int age; char addr[30]; public: void display() { cout<<"age:"<<age<<endl; cout<<"addr:"<<addr<<endl; }};仔細觀察第一行: class student:public stud 在class后面的student是新建的類名。冒號后面的stud表示是已存在的基類。在stud之前有一關鍵字public,用來表示基類stud中的成員在派生類student中的使用權限。基類名前有public的稱為“公用派生類”。 定義派生類的一般形式: class 派生類名:[引用權限] 基類名 { 派生類新增加的數據成員 派生類新增加的成員函數 }; 引用權限可以是private和public。不寫的話默認是private。 派生類包括基類成員和自己增加的成員,派生類的成員函數在引用派生類自己的數據成員時,按前面介紹過的規則處理(即私有數據成員只能被同一類中的成員函數引用,公用成員可以被外界引用)。而對從基類繼承來的成員的引用并不是簡答地把基類的私有和公用成員直接作為派生類的私有成員和公用成員,而要根據基類成員的引用權限和派生類聲明的引用權限共同決定。
公用派生類 在聲明一個派生類的時候將基類的引用權限指定為public的,該類稱為基類的公用派生類。 在公用派生類中,基類的公用成員和保護成員仍然稱為派生類中的公用成員和保護成員,而基類的私有成員不能被派生類引用,即成為派生類不可訪問的成員,只有基類的成員函數可以引用它。基類的成員在公用派生類中的引用權限見下表:
基類 | 私有成員 | 公用成員 |
---|---|---|
公用派生類 | 不可訪問的成員 | 公用成員 |
由于基類的私有成員對派生類來說是不可訪問的,因此在派生類的show函數中直接引用基類的私有數據成員name是不允許的。可以通過基類的公用成員函數來引用基類的私有數據成員。上面對派生類student的聲明可改為
class student:public stud{ private: int age; char addr[30]; public: void show() { display();//引用基類的公有成員函數允許。 cout<<"age:"<<age<<endl; cout<<"addr:"<<addr<<endl; }};在派生類成員函數show中引用基類的公用成員函數display,通過display引用基類stud中的私有數據num、name和sex。可以這樣寫main函數(假設對象a中已有數據);
void main(){ student a;//定義一個student派生類的對象a ... a.show();//輸出a對象的5個數據}在主函數中如下程序: a.display();//正確,從基類繼承的公用成員函數 a.age=18;//錯誤。外界不能引用基類的私有成員
私有派生類 在聲明一個派生類時,將基類的引用權限指定為private的,該類稱為基類的私有派生類。 在私有派生類中,基類的公用成員和保護成員成為派生類的私有成員,基類的私有成員稱為派生類的不可訪問成員。只有基類的成員函數可以引用它。基類的成員在私有派生類中的引用權限見下表:
基類 | 私有成員 | 公用成員 |
---|---|---|
私有派生類 | 不可訪問的成員 | 私有成員 |
如果派生類首行改為
class student;private stud{ private: int age; char addr[20]; public: void show() { display();//基類的公有成員函數變成派生類的私有函數 cout<<"age:"<<age<<endl; cout<<"addr:"<<addr<<endl; }};void main(){ student a; a.display(); a.age=18;}可以看到: (1)不能通過私有派生類對象引用從基類繼承過來的任何成員; (2)在派生類的成員函數中不能訪問基類的私有成員,但可以訪問基類的公用成員,由于私有派生類限制太多,一般不常用。
保護成員 由protect聲明的成員稱為保護成員,不能被外界引用(這點和私有成員類似),但可以被派生類的成員函數引用。
基類 | 私有成員 | 公用成員 | 保護成員 |
---|---|---|---|
公用派生類 | 不可訪問的成員 | 公用成員 | 保護成員 |
私有派生類 | 不可訪問的成員 | 私有成員 | 私有成員 |
從前面的介紹已知基類的私有成員被派生類(不論是私有派生類還是公用派生類)繼承后變為不可訪問的成員。如果想在派生類引用基類的成員,可以將基類的成員聲明為protected。
/*派生類引用保護成員*/class stud //聲明基類{ protect: //基類保護成員 int num; char name[10]; char sex; public: //基類公用成員 void display() //基類成員函數 { cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }};class student:public stud //聲明一個公用派生類{ private: int age; char addr[30]; public: void show() { cout<<"num:"<<num<<endl; //引用基類的保護成員,合法 cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; cout<<"age:"<<age<<endl; //引用派生類的私有成員,合法 cout<<"address:"<<addr<<endl; }};void main(){ student a; //a是派生類student類的對象 a.show(); //合法,show是派生類中的公用成員函數// a.num=10023; 錯誤,外界不能訪問保護成員}派生類的構造函數 派生類從基類繼承了非私有成員函數和數據成員,但在建立派生類對象時,系統只執行派生類的構造函數,而不會自動執行基類的構造函數。也就是說,基類的構造函數是不能繼承的。如果基類的構造函數包含對對變量的初始化,那么在建立派生類對象時,由于沒有執行基類的構造函數,因而就會使基類的變量未初始化。所以在設計派生類的構造函數時,不僅要考慮派生類所增加的變量初始化,還應當考慮基類的變量初始化。在執行派生類的構造函數時,應當調用基類的構造函數。
/*派生類的構造函數*/#include<string.h>#include<iostream.h>class stu{ protected: int num; char name[20]; char sex; public: stud(int n,char nam[],char s) { num=n; strcpy(name,nam); sex=s; }~stud(){}};class student:public stud{ private: int age; char addr[30]; public: student(int n,char nam[],char s,int a,char ad[]):stud(n,nam,s) {age=a; strcpy(addr,ad); } void show() { cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }~student(){}};void main(){ student a(10010,"Wangjun",'f',22,"420hust"); student b(10010,"Chenglin",'m',18,"321hust"); a.show(); b.show();}請注意派生類構造函數首行的寫法:
student(int n,char nam[],char s,int a,char ad[]):stud(n,nam,s)其一般的形式為 派生類構造函數函數名(參數表列):基類構造函數名(參數表列) 派生類構造函數名后面括號內的參數表列包括參數的類型和參數名。基類構造函數名后面括號內的參數表列只有參數名而不包括參數類型。從基類的聲明中可以中可以看到基類構造函數stud有3個參數,派生類構造函數有5個參數,前三個是用來傳遞給基類構造函數的,后面2個是用來對派生類所增加的變量初始化的。
在上例中也可以將派生類構造函數在類外面定義,而在類的聲明中只寫函數的聲明
student(int n,char nam[],char s,int a,char ad[]);在類的外面定義派生類構造函數:
student::student(int n,char nam[],char s,int a,char ad[]):stud(n,nam,s){ age=a; strcpy(addr,ad);}注意:在類中對派生類構造函數作聲明時,不包括基類構造函數名和參數表列,只在定義函數時才將它列出。
在建立一個對象時,由派生類構造函數先調用基類構造函數,然后再執行派生類構造函數本身。對上例來說,先初始化num,name,sex,然后再初始化age和addr。 在對象消失時,先執行派生類析構函數,再執行其基類析構函數。
新聞熱點
疑難解答
圖片精選