体验Visual Studio 2005中C++语言
Viusal Studio2005极大地丰富了它的库,可以说是科研背后的清障机和加速器,对于这一点,我想大部分人都是这么认为的。它带来的大量工具及新增的功能性函数使 开发 人员的生活越来越快乐、简单。但对于我来说,所有这些与Visual Studio2005在C++上做的改变相
Viusal Studio2005极大地丰富了它的库,可以说是科研背后的清障机和加速器,对于这一点,我想大部分人都是这么认为的。它带来的大量工具及新增的功能性函数使
开发人员的生活越来越快乐、简单。但对于我来说,所有这些与Visual Studio2005在
C++上做的改变相比却都显得是那么苍白无力。这篇文章中,我着重叙述即将向用户发行的Viusal Studio2005版本给
C++带来的变化。
一、对下划线说再见
Visual Studio
.NET 2002在C++中引入了可扩展的托管,这种扩展带来的关键词以双下划线开始,例如__gc 和 __property。这个版本发行后的这些年来,我写了大量带有双下划线的代码,我不得不承认我从来都不喜欢这一点,我完全明白真正的原因是什么:双下划线将关键词标志为特殊地扩展,以区分编译器的标准编译规则,在理论上,可以充分使用可扩展的托管,使用其他的编译器编译它,这将忽略所有带双下划线关键词。
解决方案:微软发现了一个解决方法来改变这种语言而不是替换这种语言。但是这种妥协带来了以下结果:
1、
开发者发现这种语法不自然而且看上去也很不舒服。
2、不能尽其所能。
例如,下面是托管C++声明属性的例子:
clearcase/" target="_blank" >cc66" width="90%" align="center" bgcolor="#dadacf" border="1">
public __gc class Foo
{
// hundreds of lines of code
__property String* get_Text();
// hundreds of lines of code
__property void set_Text(String*);
// hundreds of lines of code
}; |
我相信,有良好
编程习惯的
程序员会将get与set紧挨者使用,并且会紧接着又声明所有下面需要使用的变量。但是语言并不管这些,它不能提供封闭的括号来界定结构,来让你声明"这是一个作为单元的属性"。所以当它运行时显得不自然并且与其他.NET语言也格格不入。
面对这些你能做什么?唯一的方法是将C++与CLI自然地结合起来,反之也就是真正改变C++。如果你将这么作,一种自然完美的语言将给你带来巨大的自由,当你编程时就再也不会需要双下划线了。
二、生命期与作用域
我非常喜欢明确地销毁对象。实际上,我也很喜欢垃圾收集器。可能我要说的更多,事实上,虽然它们有着各地的位置,而且对于我来说都需要,但如果我正在创建的对象仅仅操作内存,如果使用后不需要我释放内容我将会非常高兴。但内存管理是如此的虚弱无力,当我的对象占用非托管的资源时,例如一个
数据库连接,一个文件对象或类似的对象,我需要自己控制。我需要确认一旦不需要的时候它就消亡。Dispose模式试图处理这些情况,但它并不是自觉的行为。封闭的括号也许是一种很好地解决途径。
在普通的非托管C++中,以下的代码说明了你不得不做的工作:
//this is a code fragment
{
try
{
Foo* f=new Foo(/* params */);
//all kinds of code, some of which might throw exceptions
delete f;
}
catch (/* something */)
{
delete f;
//whatever else, or rethrow;
}
} |
如果在堆上创建对象显的是那么的容易:
//this is a code fragment
{
Foo f;
//all kinds of code, some of which might throw exceptions
} |
当变量f超出作用域,无论是否是因为异常,它都自动消亡,这非常自然而且令人高兴、满意。
当这个对象在托管堆上,你不需要删除它,它将被垃圾搜集器清除。但是,如果它占用了一个托管资源,你可能想通过Dispose()方法来清除它,C#为这么做提供了using构造,但是它仍然不象我们的堆例子那样简单。
在新版本的语言中(以前叫C++/CLI),你可以不依赖于对象的种类来创建它,你可以在堆上创建一个托管对象,并且它可以在超出作用域后明确地被销毁。如果愿意的话,你还可以在托管堆上创建,这完全根据你的选择而定。
这种变化带来了其他的后果。最具深远意义的结果是你可以轻松地将任意对象放入
模板集或作为另外一个类的成员变量。你可以充分发挥C++的力量来管理对象的生命期,而不是仅仅在堆上分配它并等待垃圾处理器来处理。
三、析构和终结
当你书写一个可以被其他语言使用的垃圾收集对象时,将发生什么?你针对这个对象是否已经写了一个析构函数?当你正在使用C++,你可以在堆上创建对象,当超出作用域范围后,对象的析构函数将自动运行。当C#或
VB应用(不能在堆上创建垃圾收集对象)使用这个对象时将发生什么?这种情况被以一种精巧的方法实时处理。它将对象的析构函数转换为Dispose()方法来使用,所以,拥有析构函数的C++/CLI对象都可以任意使用。
如果你用C#或VB写了一个带有Dispose()方法的类,你可能已经写了一个终结函数,对于终结函数C++/CLI也有一种非常简单的语法。就象foo对象的析构函数叫做~Foo()一样,foo对象的终结函数叫做!Foo(),这两种方法都提醒你他们与构造函数相反。
当一个对象在托管堆上创建后,终结函数开始运行但从不被处理(因为执行的Dispose的级别要高于终结函数)。从某种意义上说,它是一个防护网,使你确信对象能释放其占用的非托管资源。即使使用对象的开发人员忘记了处理它。
四、指针与句柄
对于扩展的托管C++来说,一个主要的限制是C++语言没有变化,两种不同的事情使用相同的符号。"*"的意思要根据代码的上下文而定,试着看看下行代码:
Foo对象在那里创建?内存是否会被自动清除?是否可以象下面代码那样对于指针使用如下算法:
答案依赖于foo是否使用__gc关键词声明,如果它是一个垃圾收集对象,它只能在托管堆上创建,而不能在本地堆、不能在栈上创建。另一方面,如果没有使用__gc关键词声明,这行代码将在本地堆上给对象分配内存,这时候你必须记住使用"delete"来释放它。
一旦编译器的作者拥有了修改语言的自由,正如C++/CLI已经发生的那样,你大可不必担心类对象来自那里,它在哪里存在。你完全可以通过不同的语法来告之对象它应该存在在哪里。
这叫做一个句柄,起初绝大多数C++开发组将^这个符号称为"脱字符号或帽子",现在都叫做帽子。就象指针那样,你从处理*或->符号中解脱出来。这种变化带来的冲击绝大部分是在你的头脑里,你只要看实例的声明就能判断对象生命期的管理,而不用返回查看类的声明。
说到类的声明,__gc and __nogc已经不再存在,在它们的位置上是一些比较"Cool"的、带有空格的关键词,带空格的关键词虽然看上去是两个词,但实际上是含有空格的一个词。
例如:
ref class R
{
private:
int m_a;
public:
R(int a): m_a(a) {}
}; |
你可能认为"ref"是C++/CLI中的一个新关键词,但实际上它不是,"Ref class"是一个关键词,其他的一些类似关键词是:"value class",""interface class"和"enum class"。因为以前几乎写的每一个C++程序都含有一个叫"Value"的变量,我非常高兴它没有变成一个关键词。
一个ref class 是一个托管类,一个生存在托管堆上并由垃圾收集器管理的类。正如我先前说的,你可以在栈上创建实例,编译器将通过一个隐藏的灵巧的指针来管理该对象。
五、属性
C++的属性变化非常大,因为我在文章的开篇讲述了托管C++中属性的尴尬,现在就让我们以简洁的C++/CLI版本来结束吧。
ref class R
{
private:
int m_Size;
public:
property int Size
{
int get() { return m_Size; }
void set(int val){m_Size = val;}
}
};
R r;
r.Size = 42; |
属性是否是关键词,从某种意义上可以这么说,它是一个定位型的关键词,所以你可以毫无冲突地将一个变量或函数称为属性,就象上面的代码那样,它只是在类的定义中有特殊的含义。现在的C++/CLI语言支持将属性定义为一个单独的单元,相对与以往的方式,我更喜欢新的方式,相信你也是这样。
原文转自:http://www.ltesting.net
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
|