模板
开始之前,先来看一个笑话,当问一个C++程序员怎样完成一个给定的任务时,他(她)可能会提供一打或更多的潜在解决方案列表,但又会极其详细地标出每种方案的问题之处,让你不知所措,难以选择。而Visual C++ 2005,通过C++/CLI语言联编,引入了泛型的概念,使C++程序员可进一步提高程序的开发效率。关于 .NET泛型与C++模板,尽管句法上很相似,但泛型与模板是以完全不同的方法实现的,它们之间没有任何的内置兼容性。
说到泛型与模板的差别,相信每个 .NET平台的C++程序员都会问这个问题:我该选择哪种技术呢?那些已用C++进行了数年开发(特别是用Visual C++)的人,相信早已知道答案:两种技术都具有卓越的特性,但任何一者都不是另一者的超集,使用何种技术只限于给定的任务,简而言之,没有一种技术可以适用于所有情况下的解决方案。同样,这种进退两难的状况也折磨了Visual C++程序员数年:Win32或是MFC、ATL或是WTL、COM或是C风格的DLL、#import或是CComPtr。
涉及 .NET开发的C++知识
在过去,Visual C++利用某些技术手段,可使STL中的集合与其他技术协同工作,如在活动模板库(ATL)中称为CComEnuOnSTL的模板化类,它允许一个Visual Basic客户端使用For Each来枚举由C++ COM服务器提供的STL集合的内容。虽然这种层次上的集成非常之浅,但在许多受限情况下证实非常有用。基于同样的主旨,STL.NET为C++程序员提供了标准STL库的一种扩展,这种扩展可允许在一个C++/CLI程序集内部使用的STL集合,作为泛型集合暴露给其他的 .NET程序集。
STL.NET提供了与标准STL集合相同的接口,因此,对熟悉标准STL集合与算法的C++程序员来说,不存在学习曲线。以Visual C++ 2005来作说明,STL.NET的头文件位于Cliext目录中,如果要使用STL.NET集合,例如vector,必须包含<cliext/vector>而不是标准的<vector>,另外,STL.NET集合包含在cliext命名空间中,而不是标准STL集合所使用的std命名空间。
注:Visual C++开发小组仍在努力工作使STL.NET变得更易使用,并提高它的性能。因为STL.NET仍在不断地进行新的改进,本文将不会探讨STL.NET集合的过深之处,而会从一种更高的角度来看,为什么STL.NET将会大有作为。
桥接泛型与模板
桥接泛型与模板这两个不同的世界,实属一项艰巨的任务。模板只是一个C++的概念,并只存在于编译时期;然而,泛型是一个 .NET概念,它存在于已编译的程序集中,并对所有 .NET语言可用。STL.NET所使用的解决方案是把类集当作C++模板类来实现,同时C++模板类也是 .NET引用类型,并由其实现了ICollection泛型接口。STL与STL.NET中vector的声明演示了这种设计:
//STL vector 声明
template<class _Ty, class _Ax = allocator<_Ty> >
class vector;
//STL.NET vector 声明
template<typename _Value_t>
ref class vector : Generic::ICollection<_Value_t>
在这两者的声明当中,有一些关键的不同之处,除泛型接口的实现之外,STL.NET vector并不能指定一个分配算符,只是简单地调用gcnew来分配一个新的所需元素。STL.NET集合声明时使用了ref关键字,这意味着它们都是 .NET引用类型,将会被分配在 .NET托管堆中。
使用STL.NET
除去STL.NET集合声明时的一些差异(这个差异与C++/CLI和标准C++间的句法差异有关),使用STL.NET集合与STL集合基本上一模一样。以下的控制台示例程序声明了一个vector对象,接着在集合中加入了一些其他不同类型的元素:
#include "stdafx.h"
#include <cliext/vector>
using namespace System;
using namespace cliext;
int main(array<System::String ^> ^args)
{
vector<Object^>^ v = gcnew vector<Object^>;
v->push_back(nullptr); //第一个元素为空
v->push_back(gcnew Object()); //第二个元素为一个纯对象
v->push_back(1); //第三个元素为装箱的整数
v->push_back("Element Four"); //第四个元素为字符串
return 0;
}
以上代码演示了STL.NET的一个重要特点:仍旧是非常熟悉的集合类,另一个特点是,可在一个集合中使用两种不同的编程模型,这意味着如果要查找上述代码中的整数1,可使用下列STL find算法:
//当作STL集合使用
bool containsOneSTL = find( v->begin( ), v->end( ), 1 ) != v->end();
另外,.NET中ICollection泛型接口也能用于实现同样的逻辑:
//当作 .NET集合使用
bool containsOnedotNet = v->Contains(1);
这种可在同一集合类中同时使用STL和 .NET算法的能力--而无须复制内容或提供桥接函数--允许C++/CLI程序员对任何有关集合的操作,选择最恰当的函数与库。
有关STL.NET最后一个特点是,可为用C#或VB.NET编写的 .NET程序集,无缝地提供其STL.NET集合。由于STL.NET集合实现了ICollection泛型接口,所以在类型安全上,再无任何损耗,再者,STL.NET集合使用了托管内存来存储集合中的元素,因此,在与那些提供STL.NET集合的C++/CLI程序集互操作时,再无任何性能或代码安全性方面的损耗。
.NET王国C++程序员的入场券
STL.NET代表了Visual C++产品的一个重要部分,其允许C++程序员利用他们现有的技能与经验,尽早使用上带成强大集合与算法的类库,而不至于被快速成长的 .NET世界拒之门外。
STL.NET作为一个光明的开端,将有助于C++在保持语言光荣传统的同时,成为 .NET语言开发的第一类选择。