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

關於類對象的析構問題

編輯:關於.NET

我們按照正常的思路,來探討一下這個問題。

首先是定義一個類,這裡就不說明了。

然後是創建類的對象(實例化一個類),一般有兩種方法:常規創建的方法和動態創建的方法。見代碼事例:

// 定義類
class A
{
   public:
   ~A();
};
A::~A()
{
   cout<<"析構"<<endl;
}

void main()
{
   A a;  // 常規創建的方法
   A *p = new A; // 動態創建的方法
}

何時析構?

(1)常規創建的方法就像我們創建一個內部類型的變量一樣。常規創建的對象像普通變量一樣有它自己的作用域,當常規創建的對象超出作用域時,會自動運行該對象的析構函數。

(2)動態創建的對象,只有我們主觀的去刪除指向動態對象的指針時,才會運行該對象的析構函數。我們知道指針也是一個變量,它也有自己的作用域,當指向動態對象的指針超出自己的作用域時,動態對象是不會運行析構函數的,這也就造成了“內存洩漏”。

變量的作用域其實就是我們能在代碼段裡能夠使用該變量的地方,當超出該變量的作用域,也就不能再使用該變量了。動態創建的對象的作用域,其實是委托給了指向該對象的指針,即該指針的作用域和動態對象的作用域是一體的,當指針丟失時,動態對象也就無法再使用了。這裡可能不太好理解,我下面舉一個例子。

定義類A和類B

// 定義類A
class A
{
   public:
   ~A();
};
A::~A()
{
   cout<<"析構A"<<endl;
}

// 定義類B
class B
{
   public:
   ~B();
};
B::~B()
{
   cout<<"析構B"<<endl;
}

主函數

// 主函數
void main()
{
   A* p = NULL;
   {
     p = new A;
     B a;
   }
}

運行結果:

分析過程:

A* p = NULL;

先創建一個指向類A的指針變量並負值NULL,即指針暫時不指向任何類A型的對象。

{
         p = new A;
         B b;
}

用“花括號對”重新開辟一個作用域區域。然後動態創建一個類A型的對象,並把該對象的地址賦給指針p. 下面又常規的創建了一個類B型的對象b.

當程序執行到“右花括號”的時候,對象b的作用域結束,然後執行對象b的析構函數。所以我們在結果畫面裡看到了“析構B”的信息。

但是要注意了,我們雖然在“花括號對”裡,動態創建了類A型的對象,但是該對象的作用域並不屬於該“花括號對”裡,之前說過:“動態創建的對象的作用域,其實是委托給了指向該對象的指針。”所以在其它地方我們仍然可以調用該對象,直到我們主觀的去刪除指向該對象的指針時,才執行該對象的析構函數,因此該對象也就不能在使用了。

下面看一個容易和上面混淆的例子:

// 主函數
void main()
{
   A* p = NULL;
   {
     A a;
     p = &a;
   }
}

我們在“花括號”內創建了一個類A型的對象a , 然後把該對象的地址賦給了指針p. 當程序執行到"右花括號"的時候,對象a作用域結束,執行對象a的析構函數。這時指針p就無效了。

何時不析構?

當通過常規或動態方法創建的對象的引用或指針超出作用域時,不會執行該對象的析構函數。

這裡就不再累述了,可以自己運行一個簡單的例子驗證一下。

總結:

常規方法創建的對象,只有"實際對象"超出作用域時,才會執行析構函數。

動態方法創建的對象,只有刪除指向該對象的指針時,才會執行析構函數。

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