扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:Stanley 来源:msdn中国 2007年11月19日
关键字:
下一个设计要求是:使不支持模板的其他语言(例如 C# 和 Visual Basic®)能够使用容器。最简单的策略是:使模板容器实现一个或多个系统容器接口(分到两个命名空间中),如图 2 中所示。
通常,您将希望同时支持收集和泛型接口,以使当前使用收集接口的客户端能够使用您的类型。以下是声明支持两种接口的方法:
以下是引用片段: template ref class vector : System::Collections::ICollection, System::Collections::Generic::ICollection { ... }; |
要实现系统收集命名空间的容器接口,还必须实现 IEnumerator 和 IEnumerator
以下是引用片段: generic ref class vector_enumerator : System::Collections::IEnumerator, System::Collections::Generic::IEnumerator { ... }; |
实现系统容器接口的弊端是:虽然使得元素可用,但是无法操作 STL/CLR 类型的容器。因此,额外的设计支持还应该提供泛型阴影容器类型,以使其他语言可以使用实际的容器类型。有两个常规策略可以实现这种支持:Plauger 方式和 Tsao 方式(以两个主要设计师 P. J. Plauger 和 Anson Tsao 的姓名来命名)。
可以认为 Plauger 方式提供泛型阴影类型。也就是说,您将创建阴影泛型类(可以将其称为 generic_vector)。它包含矢量模板的副本。示例如下:
以下是引用片段: generic public ref class vector_generic { vector^ m_templ; // 哎呀... public: vector_generic( vector^ ); }; |
m_templ 声明行上的“哎呀”注释表示在 .NET 下对模板使用的约束。由于存在这种约束,您不能以泛型类型存储要求实例化的模板。这是因为,两个参数化类型功能的实例化时间不同。泛型由运行时来实例化;而模板由编译器来实例化。因此,模板可以包含泛型,而泛型不能包含模板。
Plauger 方式下的解决方案为:创建一个公共泛型接口,模板和泛型均通过该接口派生。有关示例,请参阅图 3。Tsao 方式下的解决方案是根据以下事实得出的:接口始终为模板容器(在特定程序集中实例化)的引用。因此,您只需提供一个接口并实现模板即可。泛型阴影类型将被消除。
以下是引用片段: generic interface class vector_interface :ICollection {...}; template ref class vector :vector_interface, ICollection {...}; |
在任何情况下,除了那些使用程序集的人们以外,所有人都可以执行泛型实例而不是 STL/CLR 容器。这是因为,C++/CLR 下的模板不能成为公共程序集成员。下一部分中讨论了此问题。
模板为非公共程序集类型
要使 .NET 识别类型,它需要两个元素:程序代码(表示要转换为公共中间语言 (CIL) 的类型)和元数据(描述类型的详细信息)。不幸的是,模板此时还不能通过任何一个元素提供给 .NET。与析构函数一样,模板并不是为 .NET 而存在的。
.NET 仅能识别模板的具体实例;而不能识别出它们是一种模板。例如,.NET 可以识别 vector 和 vector 的 CIL 和元数据,但是不能识别共享的模板矢量,CIL 和元数据都是该模板矢量的实例。这种不可识别性的副作用是,您不能辨别模板。也就是说,您不能询问 vector 实例:“您是模板吗?如果是,请把您的参数列表和类定义传递给我好吗?”
另一方面,泛型在 CLR 2.0 中直接支持 CIL,并且具有完全支持泛型反射的扩展反射命名空间。这是您在选择设计方式(在应用程序中使用模板还是泛型类型)时,应该考虑的一个方面。还应考虑是否需要跨程序集共享。模板不能跨程序集共享,而泛型可以。因此,如果跨程序集共享对您的设计非常重要,则应选择泛型类而不是模板类。否则,您将需要提供某种形式的公共接口,来实现跨程序集的共享,正如我所介绍的有关 STL/CLR 设计的内容。
模板不能跨程序集识别的原因是:.NET 具有一个包含其源的扩展类型概念。也就是说,在 .NET 下与在本机 C++ 中不同,类型具有一个位置,在此位置名称可在共享的全局空间中自由浮动。这种全局名称混乱使得将各种组件合并到一个工作应用程序中非常困难。进一步的区别在于:命名空间将提供程序级别的解决方案,而为类型添加位置将提供程序集级别的解决方案。
也就是说,全局公共名称实际上由其程序集分配,从而避免在合并程序集时发生名称冲突。在 .NET 下,类型具有一个位置。这意味着,一个程序集的 vector 不会被识别为另一个程序集的相同 vector,因为类型已由单独的程序集名称标记。由于 CLR 提供的运行时实例化,泛型不会出现这种问题。
那么,既然存在这些约束,为什么我们还选择同时提供模板和 STL/CLR 呢?执行工作的 C++ 程序员已建立起该库和现有代码体的专业知识。我们不仅希望提供现有代码的迁移路径,还希望提供现有专业知识的迁移路径。如果您以前在 C++ 编程过程中依靠 STL,则会感到在 .NET 下缺少 STL 是一种损失。而使用 STL/CLR 则不会这样。我后来听说,计划在 STL 完成后使其可以下载使用。请继续关注!我知道我会的。
请将您的疑问和意见通过 purecpp@microsoft.com 发送给 Stanley。
Stanley B. Lippman 从 1984 年开始在 Bell 实验室与 C++ 的发明者 Bjarne Stroustrup 一起使用 C++。后来,Stan 在 Disney 和 DreamWorks 的动画部门工作过,还担任过 Fantasia 2000 的软件技术主管。此后他一直担任 JPL 的杰出顾问,以及与 Microsoft 公司 Visual C++ 团队合作的设计师。
本文摘自 2006 年 4 月发行的《MSDN Magazine》。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者