c++類的析構函數
每個類都有構造函數和析構函數。
其中,構造函數在定義對象時被調用,析構函數在對象釋放時被調用。
如果用戶沒有提供構造函數和析構函數,系統將提供默認的構造函數和析構函數。
析構函數
析構函數在對象超出作用範圍或使用delete運算符釋放對象時被調用,用於釋放對象佔用的空間。
如果用戶沒有顯式地提供析構函數,系統將提供默認的析構函數。
析構函數也是以類名作爲函數名,與構造函數不同的是,在函數名前添加一個“~”符號,標識該函數是析構函數。
析構函數沒有返回值,甚至void類型也不可以;
析構函數也沒有參數,因此析構函數是不能重載的。
這是析構函數與普通函數的最大區別。
Error"引發了異常;讀取訪問權限衝突。r是0xDDDDDDDD"
!!!析構函數不應該出現在main函數中!!!
析構函數(destructor) 與構造函數相反,當對象結束其生命週期,如對象所在的函數已調用完畢時,系統自動執行析構函數。
析構函數在每個類必須有,需要定義一個或系統默認提供一個,但不能出現在main()函數裏,
否則(析構函數出現在main函數中)就會因爲重複調用析構函數而報錯:
"引發了異常;讀取訪問權限衝突。"
“r是0xDDDDDDDD”
…
//Release函數實現,遞歸思想。
template <class T>
void Tree<T>::ReleaseTree(Node<T>* R)
{
if (R != NULL)
{
ReleaseTree(R->lchild); //**報錯位置**非實際錯誤位置
ReleaseTree(R->rchild);
delete R;
}
}
//析構函數實現,調用ReleaseTree函數。
template <class T>
Tree<T>::~Tree()
{
ReleaseTree(root);
}
而且從報錯位置來找問題根本找不到問題,而問題卻在main函數裏面
int main()
{
int data[15] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
Tree<int>target(data,15);
//target.~Tree();//實際出錯位置
//析構函數不能寫在main()裏面,執行完後會自動析構,
//否則會重複執行析構導致報錯
return 0;
}
析構函數自動執行之示例:
#include <iostream>
using namespace std;//有這句cout才能用
class CBook
{
public:
int n;
CBook():n(3)
{
int m=n;
cout<<n<<endl;
cout<<m<<endl;
printf("構造函數被調用\n");
}
~CBook()
{
printf("析構函數被調用\n");
}
} ;
int main()
{
CBook book;
cout<<book.n<<endl;
cout<<"main函數"<<endl;
return 0;
//book.~CBook()//不應該有,有則報錯
}
Result:
Analysis:
程序從main()第一句開始先執行
int main()
{
CBook book;//1;//類實例化爲對象,此時執行類體構造函數
class CBook
{
public:
int n;
CBook():n(3)
{
int m=n;
cout<<n<<endl;//1.1
cout<<m<<endl;//1.2
printf("構造函數被調用\n"); //1.3
}
依次輸出:(1.1->1.2->1.3)
之後繼續執行main()函數
cout<<book.n<<endl;//1.4
cout<<"main函數"<<endl;//1.5
return 0;
繼續依次輸出:(->1.4->1.5)
之後main函數執行結束,也就是book對象超出作用域時調用析構函數
(->1.6):
~CBook()
{
printf("析構函數被調用\n");//1.6
}
釋放book對象,因此輸出
特別注意:
析構函數不應該出現在main()函數中,否則重複析構會報錯!!!
//book.~CBook()//不應該有,有則報錯