全面解析C++中的析構(gòu)函數(shù)
“析構(gòu)函數(shù)”是構(gòu)造函數(shù)的反向函數(shù)。在銷毀(釋放)對象時(shí)將調(diào)用它們。通過在類名前面放置一個(gè)波形符 (~) 將函數(shù)指定為類的析構(gòu)函數(shù)。例如,聲明 String 類的析構(gòu)函數(shù):~String()。
在 /clr 編譯中,析構(gòu)函數(shù)在釋放托管和非托管資源方面發(fā)揮了特殊作用。
析構(gòu)函數(shù)通常用于在不再需要某個(gè)對象時(shí)“清理”此對象。請考慮 String 類的以下聲明:
// spec1_destructors.cpp
#include <string.h>
class String {
public:
String( char *ch ); // Declare constructor
~String(); // and destructor.
private:
char *_text;
size_t sizeOfText;
};
// Define the constructor.
String::String( char *ch ) {
sizeOfText = strlen( ch ) + 1;
// Dynamically allocate the correct amount of memory.
_text = new char[ sizeOfText ];
// If the allocation succeeds, copy the initialization string.
if( _text )
strcpy_s( _text, sizeOfText, ch );
}
// Define the destructor.
String::~String() {
// Deallocate the memory that was previously reserved
// for this string.
if (_text)
delete[] _text;
}
int main() {
String str("The piper in the glen...");
}
在前面的示例中,析構(gòu)函數(shù) String::~String 使用 delete 運(yùn)算符來動(dòng)態(tài)釋放為文本存儲分配的空間。
聲明析構(gòu)函數(shù)
析構(gòu)函數(shù)是具有與類相同的名稱但前面是波形符 (~) 的函數(shù)
該語法的第一種形式用于在類聲明中聲明或定義的析構(gòu)函數(shù);第二種形式用于在類聲明的外部定義的析構(gòu)函數(shù)。
多個(gè)規(guī)則管理析構(gòu)函數(shù)的聲明。析構(gòu)函數(shù):
- 不接受參數(shù)。
- 無法指定任何返回類型(包括 void)。
- 無法使用 return 語句返回值。
- 無法聲明為 const、volatile 或 static。但是,可以為聲明為 const、volatile 或 static 的對象的析構(gòu)調(diào)用它們。
- 可以聲明為 virtual。通過使用虛擬析構(gòu)函數(shù),無需知道對象的類型即可銷毀對象 - 使用虛函數(shù)機(jī)制調(diào)用該對象的正確析構(gòu)函數(shù)。請注意,析構(gòu)函數(shù)也可以聲明為抽象類的純虛函數(shù)。
使用構(gòu)造函數(shù)
當(dāng)下列事件之一發(fā)生時(shí),將調(diào)用析構(gòu)函數(shù):
使用 delete 運(yùn)算符顯式解除分配了使用 new 運(yùn)算符分配的對象。使用 delete 運(yùn)算符解除分配對象時(shí),將為“大多數(shù)派生對象”或?yàn)閷儆谕暾麑ο?,但不是表示基類的子對象的對象釋放?nèi)存。此“大多數(shù)派生對象”解除分配一定僅對虛擬析構(gòu)函數(shù)有效。在類型信息與實(shí)際對象的基礎(chǔ)類型不匹配的多重繼承情況下,取消分配可能失敗。
具有塊范圍的本地(自動(dòng))對象超出范圍。
臨時(shí)對象的生存期結(jié)束。
程序結(jié)束,并且存在全局或靜態(tài)對象。
使用析構(gòu)函數(shù)的完全限定名顯式調(diào)用了析構(gòu)函數(shù)。(有關(guān)詳細(xì)信息,請參閱顯式析構(gòu)函數(shù)調(diào)用。)
前面的列表中所述的情況將確保所有對象均可通過用戶定義的方法進(jìn)行銷毀。
如果基類或數(shù)據(jù)成員有一個(gè)可訪問的析構(gòu)函數(shù),并且派生類未聲明析構(gòu)函數(shù),則編譯器將生成一個(gè)析構(gòu)函數(shù)。此編譯器生成的析構(gòu)函數(shù)將為派生類型的成員調(diào)用基類析構(gòu)函數(shù)和析構(gòu)函數(shù)。默認(rèn)析構(gòu)函數(shù)是公共的。
析構(gòu)函數(shù)可以隨意調(diào)用類成員函數(shù)和訪問類成員數(shù)據(jù)。從析構(gòu)函數(shù)調(diào)用虛函數(shù)時(shí),調(diào)用的函數(shù)是當(dāng)前正在銷毀的類的函數(shù)。
析構(gòu)的順序
當(dāng)對象超出范圍或被刪除時(shí),其完整析構(gòu)中的事件序列如下所示:
將調(diào)用該類的析構(gòu)函數(shù),并且會執(zhí)行該析構(gòu)函數(shù)的主體。
按照非靜態(tài)成員對象的析構(gòu)函數(shù)在類聲明中的顯示順序的相反順序調(diào)用這些函數(shù)。用于這些成員的構(gòu)造的可選成員優(yōu)化列表不影響構(gòu)造或析構(gòu)的順序。
非虛擬基類的析構(gòu)函數(shù)以聲明的相反順序被調(diào)用。
虛擬基類的析構(gòu)函數(shù)以聲明的相反順序被調(diào)用。
// order_of_destruction.cpp
#include <stdio.h>
struct A1 { virtual ~A1() { printf("A1 dtor\n"); } };
struct A2 : A1 { virtual ~A2() { printf("A2 dtor\n"); } };
struct A3 : A2 { virtual ~A3() { printf("A3 dtor\n"); } };
struct B1 { ~B1() { printf("B1 dtor\n"); } };
struct B2 : B1 { ~B2() { printf("B2 dtor\n"); } };
struct B3 : B2 { ~B3() { printf("B3 dtor\n"); } };
int main() {
A1 * a = new A3;
delete a;
printf("\n");
B1 * b = new B3;
delete b;
printf("\n");
B3 * b2 = new B3;
delete b2;
}
輸出:
A3 dtor A2 dtor A1 dtor B1 dtor B3 dtor B2 dtor B1 dtor
虛擬基類
按照與虛擬基類在定向非循環(huán)圖形中顯示的順序的相反順序調(diào)用這些虛擬基類的析構(gòu)函數(shù)(深度優(yōu)先、從左到右、后序遍歷)。下圖描述了繼承關(guān)系圖。
演示虛擬基類的繼承關(guān)系圖
下面列出了圖中顯示的類的類頭。
- class A
- class B
- class C : virtual public A, virtual public B
- class D : virtual public A, virtual public B
- class E : public C, public D, virtual public B
為了確定 E 類型的對象的虛擬基類的析構(gòu)順序,編譯器將通過應(yīng)用以下算法來生成列表:
- 向左遍歷關(guān)系圖,并從關(guān)系圖中的最深點(diǎn)開始(在此示例中,為 E)。
- 執(zhí)行左移遍歷,直到訪問了所有節(jié)點(diǎn)。記下當(dāng)前節(jié)點(diǎn)的名稱。
- 重新訪問上一個(gè)節(jié)點(diǎn)(向下并向右)以查明要記住的節(jié)點(diǎn)是否為虛擬基類。
- 如果記住的節(jié)點(diǎn)是虛擬基類,請瀏覽列表以查看是否已將其輸入。如果它不是虛擬基類,則將其忽略。
- 如果記住的節(jié)點(diǎn)尚未包含在列表中,請將其添加到列表的底部。
- 向上遍歷關(guān)系圖并沿下一個(gè)路徑向右遍歷。
- 轉(zhuǎn)到步驟 2。
- 在用完最后一個(gè)向上路徑時(shí),請記下當(dāng)前節(jié)點(diǎn)的名稱。
- 轉(zhuǎn)到步驟 3。
- 繼續(xù)執(zhí)行此過程,直到底部節(jié)點(diǎn)再次成為當(dāng)前節(jié)點(diǎn)。
因此,對于 E 類,析構(gòu)順序?yàn)椋?/p>
- 非虛擬基類 E。
- 非虛擬基類 D。
- 非虛擬基類 C。
- 虛擬基類 B。
- 虛擬基類 A。
此過程將生成唯一項(xiàng)的有序列表。任何類名均不會出現(xiàn)兩次。在構(gòu)造列表后,將以相反的順序遍歷該列表,并且將調(diào)用列表中每個(gè)類(從最后一個(gè)到第一個(gè))的析構(gòu)函數(shù)。
如果某個(gè)類中的構(gòu)造函數(shù)或析構(gòu)函數(shù)依賴于要先創(chuàng)建或保留更長時(shí)間的另一個(gè)組件(例如,如果 A 的析構(gòu)函數(shù)(上圖中所示)依賴于執(zhí)行其代碼時(shí)仍存在 B),則構(gòu)造或析構(gòu)的順序特別重要,反之亦然。
繼承關(guān)系圖中各個(gè)類之間的這種相互依賴項(xiàng)本質(zhì)上是危險(xiǎn)的,因?yàn)樯院笈缮惪梢愿淖钭筮叺穆窂?,從而更改?gòu)造和析構(gòu)的順序。
非虛擬基類
按照相反的順序(按此順序聲明基類名稱)調(diào)用非虛擬基類的析構(gòu)函數(shù)??紤]下列類聲明:
class MultInherit : public Base1, public Base2 ...
在前面的示例中,先于 Base2 的析構(gòu)函數(shù)調(diào)用 Base1 的析構(gòu)函數(shù)。
顯式析構(gòu)函數(shù)調(diào)用
很少需要顯式調(diào)用析構(gòu)函數(shù)。但是,對置于絕對地址的對象進(jìn)行清理會很有用。這些對象通常使用采用位置參數(shù)的用戶定義的 new 運(yùn)算符進(jìn)行分配。 delete 運(yùn)算符不能釋放該內(nèi)存,因?yàn)樗皇菑淖杂纱鎯^(qū)分配的(有關(guān)詳細(xì)信息,請參閱 new 和 delete 運(yùn)算符)。但是,對析構(gòu)函數(shù)的調(diào)用可以執(zhí)行相應(yīng)的清理。若要顯式調(diào)用 s 類的對象 String 的析構(gòu)函數(shù),請使用下列語句之一:
s.String::~String(); // Nonvirtual call ps->String::~String(); // Nonvirtual call s.~String(); // Virtual call ps->~String(); // Virtual call
可以使用對前面顯示的析構(gòu)函數(shù)的顯式調(diào)用的表示法,無論類型是否定義了析構(gòu)函數(shù)。這允許您進(jìn)行此類顯式調(diào)用,而無需了解是否為此類型定義了析構(gòu)函數(shù)。顯式調(diào)用析構(gòu)函數(shù),其中未定義的析構(gòu)函數(shù)無效。
上一篇:Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程
欄 目:C語言
下一篇:C語言冒泡排序法心得
本文標(biāo)題:全面解析C++中的析構(gòu)函數(shù)
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/2550.html
您可能感興趣的文章
- 04-02c語言沒有round函數(shù) round c語言
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車次數(shù)的問題詳解
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入解析最長公共子串
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改


