跟下划线拜拜
在visual studio.NET中引入了对C++扩展名的处理,扩展名是以两个下划线开始的关键字,比如__gc和__property.自从上个版本发布以来,我已经写了大量的双下划线特征的代码,我坦白也不喜欢这样,我了解具体的原因是:带两个下划线的关键字作为特殊的扩展名使它们不会跟标准编译器相混淆,你可以全面的管理扩展名可以用其他的编译器来编译,它忽视__关键字。
这是一种解决方法:微软发现了一种方法不改变编程语言的改变,但是会出现下面一些结果:
·开发者发现语法不自然
·不能被完全的采用
如例,适当的C++处理方法:
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和put放在每个扩展名的右面,把潜在的变量放在旁边,但是编程语言没要求你这样做。它提供无环境支持定界结构让你明白作为一个单元是正确的,所以它是不自然的跟其它visual studio .NET语言不一样。但是你如何去处理这个问题那,唯一的方式完成C++转换成CLR反之就要改变C++.假如你想那样做,你可以有足够的自由得到自然一流的语言会给你最好的,你可以取消大量的带双划线的关键字。
生存时间和范围
我喜欢确定的解析,实际上我也喜欢碎片收集,我还能举出更多的,它们有自己的作用而且我也需要它们,假如我只在内存中构造一个对象,我希望在我自己清除它前不被清除,
所以内存管理是很复杂的。但是,如果你的对象包含一个非管理的源文件如数据库链接,一个开放文件,或者类似我要取得一个控制。我想知道它要尽快的离开,用这种模式去处理,但是它不是直接的,简单的亲密支持是最好的办法。
下面是在原始的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#为它提供了的有效的结构,但是它仍然不象堆栈那样简单。
在新一代的语言(以前是C++/CLI),你在哪里建立对象不依赖于你建立对象的种类,你可以堆栈中管理对象,它有确定的解析,但它越界时将被清除,如果你愿意你可以在管理堆里建立对象。
这种变化带来其它的结果,其中最深远的是你可以把不同的对象放在摸板中或者可以把它看成其它类的成员变量,你可以得到完整的C++生存时间周期,而不是仅仅是把它分配到相应的堆,然后等碎片收集来处理它。
解析和定稿
当你为其它语言写了碎片收集对象是,你是否为它写了解析函数?当你使用C++,你可以在堆栈构造对象,解析函数将运行当它越界时,什么事情会发生当其他C#或VB程序调用这个对象,运行时仅从简单的方式去处理,它是用dispose()来解析,任何一个C++/CLI对象都有一个可以任意调用的解析函数。
假如你在C#或VB中有dispose()的类,你可能已经写了一个定论,C++/CLI也有简便的语法为定论,就象Foo的解析是~Foo,Foo的定论是!Foo(~是比特的not,!是逻辑的not,它们都是提醒是和构造函数对立的),
Finalizer将运行当在管理堆中建立而不被调用,确信它所包含的非管理源文件被清除,即使其他调用函数忘了去解析。
指针和句柄
在C++扩展名管理中,C++的主要限制没有变化,同样的符号和语法用做完全的事情,*的含义依赖于你的代码中的其他位置的信息,你可以试试下面的代码:
Foo* pf = new Foo();
Foo对象将在哪里建立?那块内存是否被清除?我能象下面那样对指针做算法吗:
pf++;
答案依赖于Foo是否用__gc关键字声明,假如它是碎片收集对象,它只能在管理堆不是在本堆和堆栈中建立,另一方面,如果没有用__gc声明,将在本堆中分配内存给它,你必须记得去清除它。
如果编译器有自由去改变语言,就象在C++/CLI上发生的,可以忽视什么地方生存的什么类型的类,可以用不同的语法表明它在哪里生存:
Foo^ hf = gcnew Foo();
这被叫做句柄,许多C++团队好象都是用^符号来标明的,你可以用*和->来解除句柄的引用,你可以从实例的声明而不是回过头从类的声明中得到生命期的声明。例如:
ref class R
{
private:
int m_a;
public:
R(int a): m_a(a) {}
};
你可能会认为ref是C++/CLI新的关键字,但它不是,“ref class“是关键字,你可以有变量是ref而不会引起混乱,其他的关键字还有”value class“,”interface class“,”enum class“,几乎过去所有的C++程序都会有value这个变量,我很高兴value没有变成关键字。
Ref class 是一个管理类,一个被设计成生存管理队中和被碎片收集管理的类,象我前面所示的你可以在堆栈中声明一个实例,编译器会帮你找到它,加上不可见的智能指针。
特性
有很多C++特性的改变,因为我是用C++比较笨拙的特性开始的例子,所以我现在关闭比较相近的C++
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;
property是一个关键字吗?有点象,它是一个位置关键字,所以你可以有property的变量和函数,而不会引起混乱,它只会在类定义中有特殊的含义,现在在C++/CLI中有单独的单元提供特性定义,我很喜欢这样,相信你也是。