C++基礎之析構函數的介紹
析構函數(destructor) 與構造函數相反,當對象脫離其作用域時(例如對象所在的函數已調用完畢),系統自動執行析構函數。析構函數往往用來做“清理善后” 的工作(例如在建立對象時用new開辟了一片內存空間,應在退出前在析構函數中用delete釋放)。
前面的一些例子都沒有說明析構函數,這是因為所用到的類在結束時不需要做特別的清理工作。下面的程序給出了一新的Date類,其中包括一個字符串指針,用來表示月份。
- #include \"iostream.h\"
- #include \"string.h\"
- class Date
- {
- int mo,da,yr;
- char *month;
- public:
- Date(int m=0, int d=0, int y=0);
- ~Date();
- void display() const;
- };
- Date::Date(int m,int d,int y)
- {
- static char *mos[] =
- {
- \"January\",\"February\",\"March\",\"April\",\"May\",\"June\",
- \"July\",\"August\",\"September\",\"October\",\"November\",\"December\"
- };
- mo=m; da=d; yr=y;
- if(m!=0)
- {
- month=new char[strlen(mos[m-1])+1];
- strcpy(month, mos[m-1]);
- }
- else month = 0;
- }
- Date::~Date()
- {
- delete [] month;
- }
- void Date::display() const
- {
- if(month!=0) cout<<month<<\' \'<<da<<\',\'<<yr;
- }
- int main()
- {
- Date birthday(8,11,1979);
- birthday.display();
- return 0;
- }
在Date對象的構造函數中,首先用new運算符為字符串month動態分配了內存,然后從內部數組中把月份的名字拷貝給字符串指針month。
析構函數在刪除month指針時,可能會出現一些問題。當然從這個程序本身來看,沒什么麻煩;但是從設計一個類的角度來看,當Date類用于賦值時,就會出現問題。假設上面的main()修改為“
- int main()
- {
- Date birthday(8,11,1979);
- Date today;
- today=birthday;
- birthday.display();
- return 0;
- }
這會生成一個名為today的空的Date型變量,并且把birthday值賦給它。如果不特別通知編譯器,它會簡單的認為類的賦值就是成員對成員的拷貝。在上面的程序中,變量birthday有一個字符型指針month,并且在構造函數里用new運算符初始化過了。當birthday離開其作用域時,析構函數會調用delete運算符來釋放內存。但同時,當today離開它的作用域時,析構函數同樣會對它進行釋放操作,而today里的month指針是birthday里的month指針的一個拷貝。析構函數對同一指針進行了兩次刪除操作,這會帶來不可預知的后果。
如果假設today是一個外部變量,而birthday是一個自變量。當birthday離開其作用域時,就已經把對象today里的month指針刪除了。顯然這也是不正確的。
再假設有兩個初始化的Date變量,把其中一個的值賦值給另一個:
- Date birthday(8,11,1979);
- Date today(12,29,2003);
- today=birthday;
問題就更復雜了,當這兩個變量離開作用域時,birthday中的month的值已經通過賦值傳遞給了today。而today中構造函數用new運算符給month的值卻因為賦值被覆蓋了。這樣,birthday中的month被刪除了兩次,而today中month卻沒有被刪除掉。
希望以上內容對析構函數的介紹,能夠給你帶來幫助。