首页 / 软件开发 / VC.NET / 从C++到.NET:将模板映射到泛型
从C++到.NET:将模板映射到泛型2009-12-25 MSDN/ Stanley Lippman讨论 ISO-C++ 文本查询语言 (TQL) 应用程序到 Microsoft® .NET Framework 和 C++/CLI 的转换。特别是,我将深入讨论如何将模板和标准模板库 (STL) 映射到 .NET 泛型工具。尽管在 1991 年,我曾在贝尔实验室从事过 Cfront 3.0 版的最初模板实现,并曾极力提倡使用这些模板,但我建议不要在 C++/CLI 中使用模板。在 .NET 下,C++ 模板实例化的静态特性使其无法成为 C++/CLI 的“一等公民”。在语言设计中,我们说主要语言实体都要具有“一等公民”身份。以 Int 为例:19 世纪 70 年代,建立抽象数据类型的运动尝试提供某种机制,使用户定义类型能够接近原始语言类型(例如 Integer)的“一等公民”身份。因此,对语言的“一等公民”和“二等公民”进行比较始终是一种合理的方法。如果我们在 .NET Framework 下对泛型对象和模板对象进行比较,就会发现泛型为“一等公民”,而模板不但排名靠后,而且排在最后一位,因此它们不再是您的最佳选择。问题在于模板对于其所在的程序集来说为本地对象。这是因为程序集类型不是简单地按其名称来标识,而是按其位置来标识。这样,方法中在程序集之间传递的 myTemplate<int> 的两个对象将被标记为类型错误。因此模板不能作为类型的公共接口的一部分。此外,模板不具有语言互操作性。泛型紧密集成在 .NET 中,因为对底层中间语言进行了扩展以支持泛型。此外,运行库可以根据需要自动按需管理泛型的实例化。在本机编译模型中,文件是分别进行编译的,只是在运行时才链接在一起。由于本机编译模型的特性,在 C++ 中一直未解决该问题。一般来说,.NET 解决了 C++ 中因本机编译模型的原因而无法解决的三个大规模编程问题:复杂全局对象的初始化顺序(即,当对象的使用和初始化在不同文件中分别进行时,确保在首次使用对象前构造该对象)、动态堆分配内存的管理以及参数化类型的按需实例化。这些问题中的每个问题都代表了实际域解决方案中与复杂性无关的一个语言层。在 .NET 下,这些问题不复存在。由于 TQL 在很大程度上依赖于模板(特别是依赖于 STL),因此模板与泛型的问题也就成了本专栏讨论的重点。有三个要解决的主要问题,它们都非常令人头痛,因为这些工作都是我们所不想做的。首先,我的实现使用了 STL Vector 类。虽然在 C++/CLI 下 STL 当前不可用,但 .NET Framework 提供了一个等价泛型集合类型:List<T>。随后,我只需在声明中替换成该类即可。不过,我必须手动更改每个对象的用法,因为这两组操作是不相同的。(此外,我可以考虑编写自己的 Vector 类的一对一映射。我将在后面考虑对 STL 集合关联容器使用此方法。)例如,下面列出了一些 Vector 声明:typedef pair<short,short> location;
typedef vector<location> loc;
typedef vector<string> text;
typedef pair<text*,loc*> text_loc;
若要将 Vector 替换为 List,只需打开命名空间,更改类型名称,然后添加跟踪句柄 (^) 即可,因为 List 是一个引用类:using namespace System::Collections::Generic;
typedef pair<short,short> location;
typedef List<location>^ loc;
typedef List<String^>^ text;
typedef pair<text,loc> text_loc;
其次,就像您在上面的代码示例中看到的那样,本实现还使用了 C++ 标准库 Pair<> 工具。该工具对于 C++/CLI 不可用,因此我必须在此处执行一些操作。由于这是一个非常简单的实现,因此我只需看一下是否能够克隆它就可以了。结果是,在本机平台和托管平台之间不存在任何纯粹的一对一映射。而且,这也没有什么好奇怪的,因为在考虑如何使本机平台更高效运行时,您需要将托管平台视为最佳选择。(我想现在唯一未考虑到的事项应为是否能提供同样的性能。)最后,我的实现还使用了 STL Set 类。但很可惜,没有等价的泛型集合类型,因此我必须执行一些操作。我的第一个想法是实现其接口的一对一映射,只是在 .NET Framework 下我无法拦截堆分配。不过,正如您将看到的那样,实践证明这并不是一个好主意。以下是 Set 的 TQL 使用示例:class Query {
public:
// ...
private:
set<short>* vec2set( const vector<location>* );
vector<location> loc;
set<short> *solution;
};