Pure C++ 专栏... 原著:Stanley B. Lippman 欢迎来到我在MSDN杂志主持的第一个专栏!实际上,我以前写过第一个专栏,其内容完全不同——讲的是Visual Studio 2005中新的泛型编程支持。但回想起来,我 觉得那篇文章留下了太多的未解答问题。因此我另辟蹊径开设这个专栏,以便提供一个我的团队在开发 Visual C++ 2005 中的 C++/CLI 方面的概观。由此我还将写一些有关.NET泛型编程的专栏。不要忘了本专栏是基于预览版的,因此有些内容可能会改变。 什么是C++/CLI? C++/CLI描绘的是一种多元组合,此处的 C++ 当然是指 Bjarne Stroustrup 在 Bell 实验室发明的C++编程语言。它支持速度和执行 文件的大小都得到优化的静态对象模型。但除了堆内存分配以外,它不支持运行时程序对对象的更改。它允许对底层机器进行无限制的访问,但对于正在运行的程序中的活动类型、以及相关的程序基础构造,它的访问能力却非常有限、或者根本就不可能。我在微软的同事 Herb Sutter,也是C++/CLI的主架构师,认为C++是一个混凝土语言。 学习C++/CLI 一种C++/CLI语言的设计有三个层面,这三个层面也适用于所有语言:语言层语法到公共类型系统(CTS) 的映射;选择为程序员直接操作而公开的底层CLI基本组织结构 的详细程度;以及选择要提供的超越CLI直接支持的附加功能。 怎样将C++/CLI 映射到CTS? 了解底层CTS 对学习C++/CLI非常有帮助,它主要包括三个常规类类型:
在设计方面,虽然CTS到一组内置的语言类型的映射对于所有CLI语言来说都是共同的,当然,每一种CLI语言的语法各不相同。例如,在C#中,我们可以 这样来定义一个抽象基类 Shape,从这个类派生特定的几何模型对象。 abstract class Shape { ... } // C# 而在C++/CLI中,可以象下面这样写,以表示完全相同的底层引用类型: ref class Shape abstract { ... }; // C++/CLI 在底层 IL(中间语言)中,以上两种声明以完全相同的方式表示。同样,在C#中,我们可以用下面的代码来定义一个具体的 Point2D 类 : struct Point2D { ... } // C# 而在C++/CLI中写成: value class Point2D { ... }; // C++/CLI 借助 C++/CLI 支持的类类型家族表现了一种本机方式的 CTS 集成。它确定了你的语法选择,例如: class native {}; value class V {}; ref class R {}; interface class I {}; CTS 也支持枚举类类型,其行为方式与本机枚举稍微有些区别,C++/CLI对二者都提供支持: enum native { fail, pass }; enum class CLIEnum : char { fail, pass}; 同样,CTS支持其自己的数组类型,其行为也与本机数组类型有一定差别,微软同样对二者提供支持: int native[] = { 1,1,2,3,5,8 }; array<int>^ managed = { 1,1,2,3,5,8 }; 那种认为任何一种 CLI 语言比另一种语言更接近或几乎就是到底层CLI的映射是不精确的。相反,每一种CLI语言都只是表达了自己对底层CLI对象模型的一种 见解。在下一节你将更清楚地看到这一点。 CLI 的细节标准 在设计CLI语言时必须考虑的第二个设计层面是要将什么程度的底层CLI实现模型结合到该语言中。这个语言解决什么样的问题?要解决这些问题必须要什么样的工具? 此外,该语言很可能吸引哪一类程序员?
是否允许程序员处理这种值类型地址是设计CLI语言时必须要解决的问题。 存在的问题? 位于托管堆中的任何对象在垃圾回收器进行清扫收缩的过程中都有可能遭遇重新分配,指向这些对象的任何指针必须被追踪并在运行时得到更新,而程序员 无法自己手动追踪它们,因此,如果你被允许用某个可能在托管堆中的值类型的地址,那么除了本机指针外,还需要一个追踪形态的指针。 在C++/CLI 中,微软选择提供一系列在托管堆中处理值类型的寻址模式: int ival = 1024; int^ boxedi = ival; array<int>^ ia = gcnew array<int>{1,1,2,3,5,8}; interior_ptr<int> begin = &ia[0]; value struct smallInt { int m_ival; ... } si; pin_ptr<int> ppi = &si.m_ival; 典型的 C++/CLI 开发人员是一个经验丰富的系统程序员,其任务是提供底层架构以及作为基础的核心应用,以此为基础来构建未来。她必须解决可伸缩性和性能相关的问题,并且必须从系统一级来看待底层 CLI。某种 CLI 语言的细节标准反映了其程序员的面貌。 附加功能 第三个设计层面是特定语言层功能要超过被CLI直接支持的功能,这样就需要建立一种语言层支持与CLI底层实现模型之间的映射。 在某些情况下,这是做不到的,因为该语言无法调解CLI的行为,在基类的构造函数和析构函数中解决虚函数便是例子。为了在这种情况中反映ISO-C++语义,需要在每个基类的构造函数和析构函数中 重新安排虚表。这是不可能的,因为虚表操作是由运行时托管的,而非单独的语言托管。 因此,这一设计层面是优越性和可行性的折中。C++/CLI 提供的附加功能主要有三个方面:
让我们看一个简单的例子:确定性终止化问题。与对象关联的内存被垃圾回收器回收之前,若存在与之相关连的 Finalize 方法,该方法将会被调用。你可以把 该方法看作是一种超级析构函数,因为它不依赖于该对象程序的生命期,它被称为终止化。调用 Finalize 方法的时间,甚至是否调用它是未定义的。这就是垃圾回收器不确定的终止化操作含义之所在。
CLI中,引用类型的类没有类析构的概念,因此,析构函数被映射到底层实现中另外的东西上,编译器则在内部完成如下转换:
这仅仅完成了一半,还需要一种析构函数的自动调用途径。支持引用类型专用的基于堆栈的符号,也就是说其生命期与其声明的范围相关联。编译器 在内部转换符号,在托管堆中分配引用对象。随着范围的终止,编译器插入一个对 Dispose 方法的调用——用户定义的析构函数。与该对象关联的实际内存的回收仍然在垃圾回收器的掌控之下。例如如 Figure 1 所示。 那么,你是如何看待 C++/CLI 的呢? 问题和建议请发送到 purecpp@microsoft.com. |
作者简介 |
本文出自 MSDN Magazine 的 February 2005 期刊,可通过当地报摊获得,或者最好是 订阅 |
本文由 VCKBASE MTT团队 翻译
转载自原文链接, 如需删除请联系管理员。
原文链接:Pure C++(中文版),转载请注明来源!