//=====================================================================
//TITLE:
// C++ VS C#(10):建構函式與解構函式
//AUTHOR:
// norains
//DATE:
// Friday 18-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//=====================================================================
1. 建構函式與解構函式
類最不可或缺的是什嗎?沒錯,就是建構函式和解構函式。對於C++和C#而言,兩者的基礎文法是一致的,建構函式都是和類名稱同名,而解構函式就是在類名稱之前增加~標誌,如:
//C++<br /> class CMyBase<br /> {<br /> public:<br /> //建構函式<br /> CMyBase(){};</p><p> //解構函式<br /> virtual ~CMyBase(){};<br /> };<br />
//C#<br /> class CMyBase<br /> {<br /> //建構函式<br /> public CMyBase(){}</p><p> //解構函式<br /> public ~CMyBase(){}<br /> };<br />
不過在C#中,雖然我們聲明的解構函式是~CMyBase(),但在.NET實際調用的卻是Finalize()。說白了,Finalize()其實就是我們聲明的解構函式~CMyBase()的別名。那麼我們可不可以不定義~CMyBase(),而直接實現Finalize()呢?建議是最好不要。因為~CMyBase()會預設調用基類的解構函式,而Finalize()必須手工調用,存在一定的風險性。
接下來的區別,就更加擴大了兩者的區別。預設情況下,衍生類別調用的是基類的預設建構函式,如果需要調用非預設的建構函式,兩種語言都有相應的文法。
首先我們來看看C++,如果需要調用基類的非預設建構函式,那麼我們必須要在衍生類別的建構函式中明確指出,也就是明確調用基類的非預設建構函式,如:
//C++<br /> <br /> //基類<br /> class CMyBase<br /> {<br /> public:<br /> //預設建構函式<br /> CMyBase(){};<br /> <br /> //非預設建構函式<br /> CMyBase(int i){};<br /> <br /> //解構函式<br /> virtual ~CMyBase(){};<br /> };<br /> <br /> //衍生類別<br /> class CDerive:<br /> public CMyBase<br /> {<br /> public:<br /> //預設建構函式<br /> CDerive(){};<br /> <br /> //明確指出調用的是基類的非預設建構函式<br /> CDerive(int i):CMyBase(i){};<br /> <br /> //解構函式<br /> virtual ~CDerive(){};<br /> };
C#的手法和C++其實也差不多,不過這裡並不需要明確指出基類的建構函式,而是用base關鍵字替代,如:
//C#<br /> <br /> //基類<br /> class CMyBase<br /> {<br /> //預設建構函式<br /> public CMyBase(){}</p><p> //非預設建構函式<br /> public CMyBase(int i){}</p><p> //解構函式<br /> public ~CmyBase(){}<br /> };</p><p> class CMyDerive:<br /> CMyBase<br /> {<br /> //預設建構函式<br /> public CMyDerive(){}</p><p> //以base關鍵字來明確指出調用的是基類的非預設建構函式<br /> public CMyDerive(int i): base(i){}</p><p> //解構函式<br /> public ~ CMyDerive (){}</p><p> };<br /> <br />
C++需要明確指出基類的名稱,而C#可以不用理會而直接用base替代,相對來說,似乎C#更為簡便一些。因為如果基類的名稱有所改變的話,那麼C#只需要修改繼承時的名字,而C++需要修改的似乎更多。那麼為什麼C++為什麼不能也增加一個類似於base的關鍵字呢?這個和繼承的機制有關。因為C#只支援單繼承,也就是只能允許有一個基類,所以base關鍵字指向非常明確;而C++因為是能夠多重繼承的,也就是說有多個基類,單單的一個base關鍵字根本無法明確指出是哪個基類。
除了base關鍵字以外,C#還支援一個this關鍵字。和base指向基類的不同,this指向的是當前類。簡單點來說,.NET在執行當前的類建構函式之前,會先執行this指向的當前類的建構函式。當然咯,this的執行次序還是在基類的建構函式完畢之後。我們來看看下面這段代碼:
class CMyBase<br /> {<br /> //預設建構函式<br /> public CMyBase()<br /> {<br /> Console.WriteLine("CMyBase()");<br /> }</p><p> //非預設建構函式<br /> public CMyBase(int i)<br /> {<br /> Console.WriteLine("CMyBase(i)");<br /> }<br /> };</p><p> class CMyDerive:<br /> CMyBase<br /> {<br /> //預設建構函式<br /> public CMyDerive()<br /> {<br /> Console.WriteLine("CMyDerive()");<br /> }</p><p> //因為這裡有this關鍵字,所以會先調用CMyDerive()函數,再調用該函數<br /> public CMyDerive(int i)<br /> : this()<br /> {<br /> Console.WriteLine("CMyDerive(int i)");<br /> }<br /> };<br /> <br />
如果你是以CMyDerive derive1 = new CMyDerive()的形式來定義一個對象,那麼輸出資訊如下:
CMyBase()
CMyDerive()
而如果是以CMyDerive derive2 = new CMyDerive(1)來定義,那麼輸出資訊如下:
CMyBase()
CMyDerive()
CMyDerive(int i)
從輸出資訊可以很明確的看出,因為在CMyDerive(int i)建構函式中用this()指定了另外一個建構函式,也就是代碼中的CMyDerive(),所以執行時就先調用了CMyDerive(),最後再是CMyDerive(int i)。
回到C++,有什麼辦法也能實作類別似的功能呢?能不能像調用基類的建構函式那樣,直接在構造列表中用本衍生類別的名字來調用別的建構函式呢?也就是說,代碼能不能這樣:
class CDerive:<br /> public CMyBase<br /> {<br /> public:<br /> CDerive(){};<br /> //採用本衍生類別的名字來調用別的建構函式,但很可惜,無法編譯通過<br /> CDerive(int i):CDerive(){};<br /> };
很可惜,在我的vs2005中會報錯:error C2614: 'CDerive' : illegal member initialization: 'CDerive' is not a base or member。
如果真的需要實現C#的this關鍵字的功能,那麼我們只能在代碼域中直接調用,如下所示:
class CDerive:<br /> public CMyBase<br /> {<br /> public:<br /> CDerive(){};<br /> CDerive(int i)<br /> {<br /> //直接調用別的建構函式<br /> CDerive();<br /> };<br /> };