//=====================================================================
//TITLE:
// C++ VS C#(10):构造函数与析构函数
//AUTHOR:
// norains
//DATE:
// Friday 18-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//=====================================================================
1. 构造函数与析构函数
类最不可或缺的是什么?没错,就是构造函数和析构函数。对于C++和C#而言,两者的基础语法是一致的,构造函数都是和类名称同名,而析构函数就是在类名称之前增加~标志,如:
//C++
class CMyBase
{
public:
//构造函数
CMyBase(){};
//析构函数
virtual ~CMyBase(){};
};
//C#
class CMyBase
{
//构造函数
public CMyBase(){}
//析构函数
public ~CMyBase(){}
};
不过在C#中,虽然我们声明的析构函数是~CMyBase(),但在.NET实际调用的却是Finalize()。说白了,Finalize()其实就是我们声明的析构函数~CMyBase()的别名。那么我们可不可以不定义~CMyBase(),而直接实现Finalize()呢?建议是最好不要。因为~CMyBase()会默认调用基类的析构函数,而Finalize()必须手工调用,存在一定的风险性。
接下来的区别,就更加扩大了两者的区别。默认情况下,派生类调用的是基类的默认构造函数,如果需要调用非默认的构造函数,两种语言都有相应的语法。
首先我们来看看C++,如果需要调用基类的非默认构造函数,那么我们必须要在派生类的构造函数中明确指出,也就是明确调用基类的非默认构造函数,如:
//C++
//基类
class CMyBase
{
public:
//默认构造函数
CMyBase(){};
//非默认构造函数
CMyBase(int i){};
//析构函数
virtual ~CMyBase(){};
};
//派生类
class CDerive:
public CMyBase
{
public:
//默认构造函数
CDerive(){};
//明确指出调用的是基类的非默认构造函数
CDerive(int i):CMyBase(i){};
//析构函数
virtual ~CDerive(){};
};
C#的手法和C++其实也差不多,不过这里并不需要明确指出基类的构造函数,而是用base关键字替代,如:
//C#
//基类
class CMyBase
{
//默认构造函数
public CMyBase(){}
//非默认构造函数
public CMyBase(int i){}
//析构函数
public ~CmyBase(){}
};
class CMyDerive:
CMyBase
{
//默认构造函数
public CMyDerive(){}
//以base关键字来明确指出调用的是基类的非默认构造函数
public CMyDerive(int i): base(i){}
//析构函数
public ~ CMyDerive (){}
};
C++需要明确指出基类的名称,而C#可以不用理会而直接用base替代,相对来说,似乎C#更为简便一些。因为如果基类的名称有所改变的话,那么C#只需要修改继承时的名字,而C++需要修改的似乎更多。那么为什么C++为什么不能也增加一个类似于base的关键字呢?这个和继承的机制有关。因为C#只支持单继承,也就是只能允许有一个基类,所以base关键字指向非常明确;而C++因为是能够多重继承的,也就是说有多个基类,单单的一个base关键字根本无法明确指出是哪个基类。
除了base关键字以外,C#还支持一个this关键字。和base指向基类的不同,this指向的是当前类。简单点来说,.NET在执行当前的类构造函数之前,会先执行this指向的当前类的构造函数。当然咯,this的执行次序还是在基类的构造函数完毕之后。我们来看看下面这段代码:
class CMyBase
{
//默认构造函数
public CMyBase()
{
Console.WriteLine("CMyBase()");
}
//非默认构造函数
public CMyBase(int i)
{
Console.WriteLine("CMyBase(i)");
}
};
class CMyDerive:
CMyBase
{
//默认构造函数
public CMyDerive()
{
Console.WriteLine("CMyDerive()");
}
//因为这里有this关键字,所以会先调用CMyDerive()函数,再调用该函数
public CMyDerive(int i)
: this()
{
Console.WriteLine("CMyDerive(int i)");
}
};
如果你是以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:
public CMyBase
{
public:
CDerive(){};
//采用本派生类的名字来调用别的构造函数,但很可惜,无法编译通过
CDerive(int i):CDerive(){};
};
很可惜,在我的vs2005中会报错:error C2614: 'CDerive' : illegal member initialization: 'CDerive' is not a base or member。
如果真的需要实现C#的this关键字的功能,那么我们只能在代码域中直接调用,如下所示:
class CDerive:
public CMyBase
{
public:
CDerive(){};
CDerive(int i)
{
//直接调用别的构造函数
CDerive();
};
};