構造函數 析構函數

析構函數(destructor)也是一個特殊的成員函數,它的作用與構造函數相反,它的名字是類名的前面加一個“~”符號。

在C++中“~”是位取反運算符,從這點也可以想到:析構函數是與構造函數作用相反的函數。當對象的生命期結束時,會自動執行析構函數。

具體地說如果出現以下幾種情況,程序就會執行析構函數:
①如果在一個函數中定義了一個對象(它是自動局部對象),當這個函數被調用結束時,對象應該釋放,在對象釋放前自動執行析構函數。
②static局部對象在函數調用結束時對象並不釋放,因此也不調用析構函數,只在main函數結束或調用exit函數結束程序時,才調用static局部對象的析構函數。
③如果定義了一個全局對象,則在程序的流程離開其作用域時(如main函數結束或調用exit函數) 時,調用該全局對象的析構函數。
④如果用new運算符動態地建立了一個對象,當用delete運算符釋放該對象時,先調用該對象的析構函數。

析構函數的作用並不是刪除對象,而是在撤銷對象佔用的內存之前完成一些清理工作,使這部分內存可以被程序分配給新對象使用。程序設計者事先設計好析構函數,以完成所需的功能,只要對象的生命期結束,程序就自動執行析構函數來完成這些工作。

注意:析構函數不返回任何值,沒有函數類型,也沒有函數參數。因此它不能被重載。一個類可以有多個構造函數,但只能有一個析構函數。

實際上,析構函數的作用並不僅限於釋放資源方面,它還可以被用來執行“用戶希望在最後一次使用對象之後所執行的任何操作”,例如輸出有關的信息。這裏說的用戶是指類的設計者,因爲,析構函數是在聲明類的時候定義的。也就是說,析構函數可以完成類的設計者所指定的任何操作。

一般情況下,類的設計者應當在聲明類的同時定義析構函數,以指定如何完成“清理”的工作。如果用戶沒有定義析構函數,C++編譯系統會自動生成一個析構函數,但它只是徒有析構函數的名稱和形式,實際上什麼操作都不進行。想讓析構函數完成任何工作,都必須在定義的析構函數中指定。

例9.5 包含構造函數和析構函數的C++程序。
#include<string>
#include<iostream>
using namespace std;
class Student //聲明Student類
{
   public :
   student(int n,string nam,char s ) //定義構造函數
   {
      num=n;
      name=nam;
      sex=s;
      cout<<″Constructor called.″<<endl; //輸出有關信息
   }
   ~Student( ) //定義析構函數
   {
      cout<<″Destructor called.″<<endl;
   } //輸出有關信息
   void display( ) //定義成員函數
   {
      cout<<″num: ″<<num<<endl;
      cout<<″name: ″<<name<<endl;
      cout<<″sex: ″<<sex<<endl<<endl;
   }
   private :
   int num;
   char name[10];
   char sex;
};

int main( )
{
   Student stud1(10010,″Wang_li″,′f′); //建立對象stud1
   stud1.display( ); //輸出學生1的數據
   Student stud2(10011,″Zhang_fun″,′m′); //定義對象stud2
   stud2.display( ); //輸出學生2的數據
   return 0;
}
程序運行結果如下:
Constructor called.
num: 10010
name:Wang_li
sex: f
Constructor called.
num: 10011
name:Zhang_fun
sex:m
Destructor called.
Destructor called.
(執行stud1的構造函數) (執行stud1的display函數)
(執行stud2的構造函數) (執行stud2的display函數)

(執行stud2的析構函數) (執行stud1的析構函數)


在使用構造函數和析構函數時,需要特別注意對它們的調用時間和調用順序。在一般情況下,調用析構函數的次序正好與調用構造函數的次序相反: 最先被調用的構造函數,其對應的(同一對象中的)析構函數最後被調用,而最後被調用的構造函數,其對應的析構函數最先被調用。

但是,並不是在任何情況下都是按這一原則處理的。在前邊的章節中曾介紹過作用域和存儲類別的概念,這些概念對於對象也是適用的。對象可以在不同的作用域中定義,可以有不同的存儲類別。這些會影響調用構造函數和析構函數的時機。

下面歸納一下什麼時候調用構造函數和析構函數:

  1. 在全局範圍中定義的對象(即在所有函數之外定義的對象),它的構造函數在文件中的所有函數(包括main函數)執行之前調用。但如果一個程序中有多個文件,而不同的文件中都定義了全局對象,則這些對象的構造函數的執行順序是不確定的。當main函數執行完畢或調用exit函數時(此時程序終止),調用析構函數。
  2. 如果定義的是局部自動對象(例如在函數中定義對象),則在建立對象時調用其構造函數。如果函數被多次調用,則在每次建立對象時都要調用構造函數。在函數調用結束、對象釋放時先調用析構函數。
  3. 如果在函數中定義靜態(static )局部對象,則只在程序第一次調用此函數建立對象時調用構造函數一次,在調用結束時對象並不釋放,因此也不調用析構函數,只在main函數結束或調用exit函數結束程序時,才調用析構函數。

構造函數和析構函數在面向對象的程序設計中是相當重要的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章