程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 周全解析C++中的析構函數

周全解析C++中的析構函數

編輯:關於C++

周全解析C++中的析構函數。本站提示廣大學習愛好者:(周全解析C++中的析構函數)文章只能為提供參考,不一定能成為您想要的結果。以下是周全解析C++中的析構函數正文


“析構函數”是結構函數的反向函數。在燒毀(釋放)對象時將挪用它們。經由過程在類名後面放置一個波形符 (~) 將函數指定為類的析構函數。例如,聲明 String 類的析構函數:~String()。
在 /clr 編譯中,析構函數在釋放托管和非托管資本方面施展了特別感化。
析構函數平日用於在不再須要某個對象時“清算”此對象。請斟酌 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...");
}

在後面的示例中,析構函數 String::~String 應用 delete 運算符來靜態釋放為文本存儲分派的空間。
聲明析構函數
析構函數是具有與類雷同的稱號但後面是波形符 (~) 的函數
該語法的第一種情勢用於在類聲明中聲明或界說的析構函數;第二種情勢用於在類聲明的內部界說的析構函數。
多個規矩治理析構函數的聲明。析構函數:

  • 不接收參數。
  • 沒法指定任何前往類型(包含 void)。
  • 沒法應用 return 語句前往值。
  • 沒法聲明為 const、volatile 或 static。然則,可認為聲明為 const、volatile 或 static 的對象的析構挪用它們。
  • 可以聲明為 virtual。經由過程應用虛擬析構函數,無需曉得對象的類型便可燒毀對象 - 應用虛函數機制挪用該對象的准確析構函數。請留意,析構函數也能夠聲明為籠統類的純虛函數。

應用結構函數

當以下事宜之一產生時,將挪用析構函數:
應用 delete 運算符顯式消除分派了應用 new 運算符分派的對象。應用 delete 運算符消除分派對象時,將為“年夜多半派生對象”或為屬於完全對象,但不是表現基類的子對象的對象釋放內存。此“年夜多半派生對象”消除分派必定僅對虛擬析構函數有用。在類型信息與現實對象的基本類型不婚配的多重繼續情形下,撤消分派能夠掉敗。
具有塊規模的當地(主動)對象超越規模。
暫時對象的生計期停止。
法式停止,而且存在全局或靜態對象。
應用析構函數的完整限制名顯式挪用了析構函數。(有關具體信息,請參閱顯式析構函數挪用。)
後面的列表中所述的情形將確保一切對象都可經由過程用戶界說的辦法停止燒毀。
假如基類或數據成員有一個可拜訪的析構函數,而且派生類未聲明析構函數,則編譯器將生成一個析構函數。此編譯器生成的析構函數將為派生類型的成員挪用基類析構函數和析構函數。默許析構函數是公共的。

析構函數可以隨便挪用類成員函數和拜訪類成員數據。從析構函數挪用虛函數時,挪用的函數是以後正在燒毀的類的函數。
析構的次序
當對象超越規模或被刪除時,其完全析構中的事宜序列以下所示:
將挪用該類的析構函數,而且會履行該析構函數的主體。
依照非靜態成員對象的析構函數在類聲明中的顯示次序的相反次序挪用這些函數。用於這些成員的結構的可選成員優化列表不影響結構或析構的次序。
非虛擬基類的析構函數以聲明的相反次序被挪用。
虛擬基類的析構函數以聲明的相反次序被挪用。

// 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

虛擬基類
依照與虛擬基類在定向非輪回圖形中顯示的次序的相反次序挪用這些虛擬基類的析構函數(深度優先、從左到右、後序遍歷)。下圖描寫了繼續關系圖。

演示虛擬基類的繼續關系圖
上面列出了圖中顯示的類的類頭。

  • 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 類型的對象的虛擬基類的析構次序,編譯器將經由過程運用以下算法來生成列表:

  1. 向左遍歷關系圖,並從關系圖中的最深點開端(在此示例中,為 E)。
  2. 履行左移遍歷,直到拜訪了一切節點。記下以後節點的稱號。
  3. 從新拜訪上一個節點(向下並向右)以查明要記住的節點能否為虛擬基類。
  4. 假如記住的節點是虛擬基類,請閱讀列表以檢查能否已將其輸出。假如它不是虛擬基類,則將其疏忽。
  5. 假如記住的節點還沒有包括在列表中,請將其添加到列表的底部。
  6. 向上遍歷關系圖並沿下一個途徑向右遍歷。
  7. 轉到步調 2。
  8. 在用完最初一個向上途徑時,請記下以後節點的稱號。
  9. 轉到步調 3。
  10. 持續履行此進程,直究竟部節點再次成為以後節點。
  11. 是以,關於 E 類,析構次序為:

    1. 非虛擬基類 E。
    2. 非虛擬基類 D。
    3. 非虛擬基類 C。
    4. 虛擬基類 B。
    5. 虛擬基類 A。
    6. 此進程將生成獨一項的有序列表。任何類名均不會湧現兩次。在結構列表後,將以相反的次序遍歷該列表,而且將挪用列表中每一個類(從最初一個到第一個)的析構函數。

      假如某個類中的結構函數或析構函數依附於要先創立或保存更長時光的另外一個組件(例如,假如 A 的析構函數(上圖中所示)依附於履行其代碼時仍存在 B),則結構或析構的次序特殊主要,反之亦然。
      繼續關系圖中各個類之間的這類互相依附項實質上是風險的,由於稍後派生類可以更改最右邊的途徑,從而更改結構和析構的次序。
      非虛擬基類
      依照相反的次序(按此次序聲明基類稱號)挪用非虛擬基類的析構函數。斟酌以下類聲明:

      class MultInherit : public Base1, public Base2
      ...
      

      在後面的示例中,先於 Base2 的析構函數挪用 Base1 的析構函數。
      顯式析構函數挪用
      很少須要顯式挪用析構函數。然則,對置於相對地址的對象停止清算會很有效。這些對象平日應用采取地位參數的用戶界說的 new 運算符停止分派。 delete 運算符不克不及釋放該內存,由於它不是從自在存儲辨別配的(有關具體信息,請參閱 new 和 delete 運算符)。然則,對析構函數的挪用可以履行響應的清算。若要顯式挪用 s 類的對象 String 的析構函數,請應用以下語句之一:

      s.String::~String();   // Nonvirtual call
      ps->String::~String();  // Nonvirtual call
      
      s.~String();    // Virtual call
      ps->~String();   // Virtual call
      
      

      可使用對後面顯示的析構函數的顯式挪用的表現法,不管類型能否界說了析構函數。這許可您停止此類顯式挪用,而無需懂得能否為此類型界說了析構函數。顯式挪用析構函數,個中不決義的析構函數有效。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved