日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

浅谈C++类(7)--析构函数

發布時間:2023/12/4 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈C++类(7)--析构函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

?不知不覺我都寫了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改成更大的數并不刪除它來嘗試一下,呵呵。析構函數就講到這里羅。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的浅谈C++类(7)--析构函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。