1. 程式人生 > >淺談C++類(7)--解構函式

淺談C++類(7)--解構函式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

歡迎轉載,但請標明作者 “九天雁翎”,當然,你給出這個帖子的連結更好。

 不知不覺我都寫了6講了,的確這樣講出來的學習才能迫使我真的去除錯每個書上出現的程式碼,去想些自己能講出什麼新的書上沒有的東西,這才是真的學習吧,以前看完書,做道題式的就以為自己基本都掌握了,在類這裡好像行不通,因為我的C基礎不適合這裡。。。。呵呵不說題外話了。這次講解構函式,相對於建構函式。解構函式就是在類的宣告週期結束的時候執行的函式,一般用來把一個類的資源釋放出來的傢伙。就我瞭解,JAVA好像不需要這樣的工作,他們有垃圾回收器,我看一個比較理性的程式設計師評價這種情況是有利有弊,類似的簡化讓JAVA成為了最佳商業模式開發軟體,但是讓JAVA程式設計師太脫離底層,讓他們的知識匱乏,因為編JAVA不需要那麼多知識,而且讓JAVA失去了很多底層應用。另外這樣的垃圾回收是耗資源的,當時Bjarne Strooustrup就考慮過也給C++加一個這樣的特性,但他又說,作為一個系統開發級及常用來開發驅動程式的語言,他無法接受那樣的效率損失。所以最後C++沒有加上這個特性。又講多了,看解構函式吧。

例7.0:

#include <string>
#include <iostream>
using namespace std;
bool being = true;                 //定義一個全域性bool變數
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 being = true;                          //表示這個東西存在
 }  //建構函式
 ~Fruit()                        //這就是傳說中的解構函式
 {
 being = false;                      //表示他不存在了
 } 
};
int main()
{
 {
  Fruit apple("apple");  //定義一個Fruit類物件apple
  cout <<"apple being?: "<<being<<endl;             
 }
 cout <<"apple being?: "<<being<<endl;
 return 0;
}

首先看到不要驚訝 :),我們的建構函式和解構函式都作了些什麼啊。我說過建構函式就是構造一個類物件會執行的函式,解構函式就是類生命週期結束時執行時執行的函式,不僅僅是我們的一般理解啊,從邏輯上來講,他們可以DO Everything,你首先要知道他們能幹什麼啊:)而且還要知道他們什麼時候起作用,因為我們用一個大括號把apple的定義括起來了,在大括號消失的時候,apple就需要消失了,於是這時候呼叫了解構函式。下面我們先看看可以做什麼的例子。

例7.1:

#include <string>
#include <iostream>
using namespace std;
bool being = true;
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 being = true;
 cout <<"Aha,I'm "<<name<<". I have created!"<<endl;
 }  //建構函式
 ~Fruit()
 {
 being = false;
 cout <<"Dame it!"<<"I'm "<<name<<". And who killed me?"<<endl;
 } 
};
int main()
{
 {
  Fruit apple("apple");  //定義一個Fruit類物件apple
  cout <<"apple being?: "<<being<<endl;
 }
 cout <<"apple being?: "<<being<<endl;
 return 0;
}

你執行看看,就知道了:)在一個物件定義的時候他會高呼自己被創造了,當他消失的時候他會宣佈自己的死亡:)好的,Fruit的物件看起來已經知道自己什麼時候有生命了,讓我們來看看到底什麼時候吧。

例7.2:

#include <string>
#include <iostream>
using namespace std;
bool being = true;
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 being = true;
 cout <<"Aha,I'm "<<name<<". I have created!"<<endl;
 }  //建構函式
 ~Fruit()
 {
 being = false;
 cout <<"Dame it!"<<"I'm "<<name<<". And who killed me?"<<endl;
 } 
};
Fruit banana("banana");
void Fb()
{
 cout<<"我是一個函式的開始"<<endl;
 Fruit pear("pear");
 cout<<"我是一個函式的結束"<<endl;
}

int main()
{
 cout<<"我是程式的開始"<<endl;
 Fb();
 cout<<"我是for迴圈的開始"<<endl;
 for(bool bi = true;bi;bi=false)
 {
 Fruit orange("orange");
 cout<<"我是for迴圈的結束"<<endl;
 }
 {
  cout<<"我是語句塊的開始"<<endl;
  Fruit apple;  //第一種情況,語句塊中建立。
  cout<<"我是語句塊的結束"<<endl;
 }
 cout<<"我是程式的結束"<<endl;
 return 0;
}

就這個程式執行的情況來看,一個類的生命週期和一個普通變數的生命週期類似,全域性變數最先建立,程式結束時結束,函式體內的變數呼叫時建立,函式結束時結束,for迴圈內的變數在for迴圈結束時結束,語句塊內的變數在語句塊結束時結束。本來Bjarne stroustrup就宣稱他希望讓類就像內建型別一樣使用,看來他不是說著好玩的:)這裡要說明的是,即使你沒有定義解構函式,系統也會像定義預設建構函式一樣幫你定義一個。讓我們看看什麼時候需要解構函式呢?

例7.3:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 cout <<"Aha,I'm "<<name<<". I have created!"<<endl;
 }  //建構函式
 Fruit(Fruit &aF)           //還記得我嗎?我是複製建構函式
 {
  name = "another " +aF.name;             
 }
 ~Fruit()
 {
 cout <<"Dame it!"<<"I'm "<<name<<". And who killed me?"<<endl;
 } 
};

int main()
{
 cout<<"main begin"<<endl;
 cout<<"created *P"<<endl; 
 {
  Fruit *p = new Fruit; 
  cout<<"created another apple"<<endl;
  Fruit apple(*p);
 }

 
 cout<<"main end"<<endl;
 return 0;
}

執行這個程式你發現什麼了?對,首先,運行復制建構函式就不執行構造函數了,因為another apple沒有宣佈自己的誕生,其次,當語句塊消失的時候another apple自動呼叫了解構函式,他宣佈他“死”了,但是動態建立的由*p指向的物件雖然宣佈自己誕生了,但是卻重來沒有宣佈自己死過,哪怕程式結束了也是這樣!!不知道vc有沒有回收記憶體的措施,不然我甚至懷疑你要是重複除錯這個程式,可以使你的機子崩潰,當然,假如可以的話將不知道需要多少次,但是理論上確實可以的。這就是記憶體洩露!作為一個C++程式設計師,需要了解的東西比一個JAVA程式設計師要多的多,回報是你能做的事情也多地多!這就是你需要記住的一個,動態建立的物件,記得手動把它撤銷。就像下面的例子一樣。

例7.4:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 cout <<"Aha,I'm "<<name<<". I have created!"<<endl;
 }  //建構函式
 Fruit(Fruit &aF)           //還記得我嗎?我是複製建構函式
 {
  name = "another " +aF.name;             
 }
 ~Fruit()
 {
 cout <<"Dame it!"<<"I'm "<<name<<". And who killed me?"<<endl;
 } 
};

int main()
{
 cout<<"main begin"<<endl;
 cout<<"created *P"<<endl; 
 {
        Fruit *p = new Fruit; 
  cout<<"created another apple"<<endl;
  Fruit apple(*p);
  cout<<"delete p"<<endl;
  delete p;
 }

 
 cout<<"main end"<<endl;
 return 0;
}

這樣才能保證你的機子不會崩潰。當你刪除指標的時候系統幫你自動呼叫了物件的解構函式,假如上面的例子還不能摧毀你對自己自己記憶體足夠大的信心的話,看下面的例子;

例7.5:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個類,名字叫Fruit
{
 string name;     //定義一個name成員          
 string colour;   //定義一個colour成員
public:
 void print()              //定義一個輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 cout <<"Aha,I'm "<<name<<". I have created!"<<endl;
 }  //建構函式
 Fruit(Fruit &aF)           //還記得我嗎?我是複製建構函式
 {
  name = "another " +aF.name;             
 }
 ~Fruit()
 {
 cout <<"Dame it!"<<"I'm "<<name<<". And who killed me?"<<endl;
 } 
};

int main()
{
 cout<<"main begin"<<endl;
 cout<<"created *P"<<endl; 
 {
        Fruit *p = new Fruit[10]; 
  cout<<"created another apple"<<endl;
  Fruit apple(*p);
  cout<<"delete p"<<endl;
  delete []p;
 }

 
 cout<<"main end"<<endl;
 return 0;
}

你會發現建立一個物件的陣列時,分別為每一個呼叫了建構函式,刪除一個動態陣列物件的時候系統幫你自動為每一個呼叫了解構函式,還不了賴嘛,但是別忘了p前面的[]表示這是個陣列,更別忘了刪除它,你可以把10改成更大的數並不刪除它來嘗試一下,呵呵。解構函式就講到這裡羅。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述