托管C++、C++/CLI、CLR

一、什么是托管C++?

  在回答这个问题,首先要搞清楚什么是"托管"(Managed)。托管是.NET的一个专门概念,它是融于通用语言运行时(CLR)中的一种新的编程理念,所以咱们彻底能够把"托管"视为".NET"。那么什么是"通用语言运行时"?通用语言运行时是.NET 框架应用程序的执行引挚。它提供了许多服务,其中包括:代码管理(装入和执行)、类型安全性验证、元数据(高级类型信息)访问、为管理对象管理内存、管理代码,COM对象和预生成的DLLs(非管理代码和数据)的交互操做性、对开发人员服务的支持等等。

  也就是说,使用托管C++意味着,咱们的代码能够被CLR所管理,并能开发出具备最新特性如垃圾自动收集、程序间相互访问等的.NET框架应用程序。

  由托管概念所引起的C++应用程序包括托管代码、托管数据和托管类三个组成部分。  

  (1) 托管代码:. Net环境提供了许多核心的运行(RUNTIME)服务,好比异常处理和安全策略。为了能使用这些服务,必需要给运行环境提供一些信息代码(元数据),这种代码就是托管代码。全部的C#、VB.NET、JScript.NET默认时都是托管的,但Visual C++默认时不是托管的,必须在编译器中使用命令行选项(/CLR)才能产生托管代码。

  (2) 托管数据:与托管代码密切相关的是托管数据。托管数据是由公共语言运行的垃圾回收器进行分配和释放的数据。默认状况下,C#、Visual Basic 和 JScript.NET 数据是托管数据。不过,经过使用特殊的关键字,C# 数据能够被标记为非托管数据。Visual C++数据在默认状况下是非托管数据,即便在使用 /CLR 开关时也不是托管的。

  (3) 托管类: 尽管Visual C++数据在默认状况下是非托管数据,可是在使用C++的托管扩展时,可使用"__gc"关键字将类标记为托管类。就像该名称所显示的那样,它表示类实例的内存由垃圾回收器管理。另外,一个托管类也彻底能够成为 .NET 框架的成员,由此能够带来的好处是,它能够与其余语言编写的类正确地进行相互操做,如托管的C++类能够从Visual Basic类继承等。但同时也有一些限制,如托管类只能从一个基类继承等。须要说明的是,在托管C++应用程序中既可以使用托管类也可使用非托管类。这里的非托管类不是指标准C++类,而是使用托管C++语言中的__nogc关键字的类。html

 

二、为何使用托管C++前端

  除了能够充分发挥.NET框架新特性外,使用托管C++还有下列好处:程序员

  (1) 因为在同一个应用程序中,甚至是同一个文件中,咱们能够同时使用托管C++和传统的非托管C++来编写,于是咱们能够充分利用两种C++所带来的好处,而且可将代码和组件快速移植到.NET框架中。数据库

  (2) 使用托管能够从任何一个.NET框架兼容语言中调用一个C++组件,也可调用非托管DLL、其它库以及类等。编程

  (3) 能够直接从非托管代码中访问.NET框架。后端

  总而言之,使用托管C++是C++程序员编写.NET框架应用程序最好的一种选择,在充分理解.NET框架基础上,避免了使用其余语言如C#、VB.NET所带来的额外开销。安全

  为何使用C++托管扩展网络

  微软既要考虑Visual C++的兼容性,又要让传统C++语言具有足够的能力开发.NET应用程序,因而在新版本的Visual C++中,引入了C++托管扩展。app

  在整个Visual Studio开发套件中,微软为了迎合.NET应用程序开发模式的要求,几乎对每一个工具都做了或大或小的改进。其中,VB的变革力度应用微软各类软件产品之最。可是太大的变革每每会带来兼容性问题,特别是新版本的VB宣称其只能开发托管的应用程序(也就是.NET应用程序),因此对开发人员来说,这确定意味着过去使用VB编写的代码在新版本VB上进行从新构造的难度会很大。VB之前就在版本兼容性方面有着不如人意的历史—— 在VB四、VB五、VB6之间进行升级,会让开发人员付出不少辛苦。如今,因为VB的体系进行了很大的改动,因此版本兼容性问题会更严重一些—— 笔者已经在微软几个官方讨论组中看到了一些开发人员和相关人士对此表示出来的担心,并看到不止一个开发人员对新版本VB在兼容性方面存在问题提出质疑甚至是批评。框架

  做为微软开发套件中的另外一位“元老”—— Visual C++,咱们对其提供完整的.NET开发支持感到高兴的同时也一样担忧它的版本兼容性问题—— Visual C++该不会也和VB同样,完全与MFC和ATL分裂吧?答案是:不可能!

  这是一个使人振奋的回答,下面就让咱们花一点时间来了解新版本Visual C++是怎样处理变革和向下兼容之间的关系的。

  另外,之因此微软对VB进行那样大的改革,是由于微软认为VB一般适用于快速应用程序领域,这些领域通常包含对效率要求不是很高的数据库前端应用程序或后端业务组件。当更为优秀的.NET框架发布以后,微软就为VB换了换“心脏”,以期大幅度加强VB的功能,使之成为快速开发.NET应用程序的主力军。而对于Visual C++这样一个在许多传统领域依然宝刀不老的工具,固然不能急躁冒进,将已有的功能丢弃。因此,在新版本的Visual C++中,采用了一种更为折衷的方法—— 扩展示有C++语言,让Visual C++在编写纯粹的.NET应用程序的同时,依然能够利用其成熟的技术进行未托管的应用程序的开发。

  C++托管扩展是一个对现行C++语言进行扩展的集合,这个集合能够帮助Visual C++的开发人员编写.NET Framework应用程序。因为是对语言作了扩展,而不是完全去掉原先C++语言的功能,因此在托管扩展中,开发人员能够在同一个应用程序中混合使用传统未托管的代码和新型的托管的代码。这样作获得的一个直接好处是,应用程序既能够享受未托管的代码特性也能够享受托管的代码特性。对组件开发也是同样,传统组件能够很容易被包装(wrapper)成.NET 框架组件,充分保障已有工做的投资。

  在实际工做中,若是开发人员遇到下列开发需求,使用托管扩展将是最佳选择:

  ● 须要快速地将未托管的C++应用程序合并到.NET框架中

  对于之前开发的传统未托管的C++应用程序,由于开发人员能够在同一个应用程序中(甚至是在同一个文件中)混合使用两种类型的代码,因此托管扩展为实现两种代码的无缝转化提供了一种平滑的转化方式。

  开发人员能够继续使用未托管的C++来编写组件,以利用语言自己强大的功能和灵活性。而后,为了让.NET 框架应用程序顺利访问这个传统组件,开发人员可使用托管扩展编写一个很小的、转换效率很高的包装(wrapper)程序。

  ● 须要让任何一种与.NET框架相容的语言能够访问C++组件

  托管扩展支持从任何.NET 框架相容语言来调用C++类。调用之因此能够实现,是由于使用托管扩展能够编写简单的包装类来对访问方暴露对应的C++类和方法。这些包装类都是托管的,并能够从其余.NET框架相容程序中进行调用。在调用过程当中,外包类在托管的类和未托管的类之间扮演了映射层的角色—— 它让方法调用直接传递到未托管的类中。另外,须要特别指出的是,托管扩展支持对任何未托管的DLL或库的调用。

  ● 须要从未托管的代码中访问.NET框架类

  为了获得更多的功能,在未托管的代码中,能够访问.NET 框架中的类。使用托管扩展,能够从C++代码中直接建立、调用一个.NET 框架类。在实际编程中,能够像处理普通未托管的C++类同样对待对托管的类的处理。另外,在.NET框架中提供了对未托管的COM的调用支持,能够编写未托管的代码直接访问。

  由于托管的代码和未托管的代码各有优势,在实际工做中,开发人员能够根据项目的实际状况,灵活选择二者的使用。在某些追求访问效率的状况下,经过.NET 框架提供的COM接口进行访问能够收到比较好的运行效果;而在某些须要快速完成任务的状况下,利用.NET 框架提供的简便性进行工做会让开发人员倍感轻松。

  托管C++并不是独立存在的编程语言,而仅仅是微软对C++的一个语法扩展,容许C++程序员在.NET框架和CLR的基础上进行托管编程。与C#和Visual Basic .NET相比,其主要优势是旧代码能够比较快地移植到新的平台上,并且即便不彻底重写代码,也能够经过互操做在同一个模块中无缝整合托管和非托管代码,重新的.Net框架中获益。.Net框架封装了大量的API,例如网络访问、字符串操做、数据访问、XML服务、图形界面控件库、邮件服务、加密服务、文件输入/输出,甚至是WMI管理,也使得应用程序员能够编写更加简洁的代码。目前只有托管C++及其后继者C++/CLI能够作到无缝整合托管和非托管代码,而在托管代码中调用COM的速度又至关慢,因此常常被用于其余语言和非托管代码之间的桥梁。

  托管C++容许程序员编写托管代码,内存管理的工做如今可让CLR去自动处理,访问时也增长了类型检查,减小了缓冲区溢出和内存泄漏的危险,增长了程序的稳定性,可是在性能敏感的应用中,庞大的.NET框架和缓慢的自动内存管理并非必要的,传统非托管代码仍然是一些人的首选。

三、什么是CLR

CLR经常使用简写词语,CLR是公共语言运行时,Common Language Runtime)和Java虚拟机同样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集),并保证应用和底层操做系统之间必要的分离。

 

四、什么是C++/CLI  

http://baike.baidu.com/view/459502.htm

C++/CLI简介http://blog.csdn.net/eric_jo/article/details/4184916

 

五、托管C++与标准C++的主要区别

  尽管托管C++是从标准C++创建而来的,但它与标准C++有着本质上的区别,这主要体如今如下几个方面:

  (1) 普遍采用"名称空间"(namespace)

  名称空间是类型的一种逻辑命名方案,.NET使用该命名方案用于将类型按相关功能的逻辑类别进行分组,利用名称空间可使开发人员更容易在代码中浏览和引用类型。固然,咱们也可将名称空间理解成是一个"类库名"。

   尽管很早Microsoft就在Visual C++中支持名称空间的编程方式,可是不多引发Visual C++程序员的广泛关注。如今在托管C++程序中,咱们必须使用这一方式,即便用#using和using关键字。例以下面的简单程序代码是在控制台上输出"Hello World":
 

#using
 using namespace System;


 int main(void)
 {
     Console::WriteLine(S"Hello World");
     return 0;
 }


  代码中,#using是用来将一个元数据文件输入到托管C++程序中,这些文件能够是包含托管数据和结构的MSIL (Microsoft intermediate language,微软中间语言)文件,如DLL、EXE、OBJ文件等。mscorlib.dll是.NET框架的一个核心类库,包含主要的名称空间 System。程序的第二行代码"using namespace System;"用来使用System名称空间。System是.NET框架根名称空间,包含最基本的类型,如用于数据流的输入/输出的System:: IO等。

  在对托管C++程序开发的不断深刻,咱们不久就会发现,许多类型的引用都要在程序的前面使用#using和using来进行。

  (2) 基本数据类型的变化

  咱们知道,标准C++语言的数据类型是很是丰富的。而托管C++的数据类型更加丰富,不只包含了标准C++中的数据类型,并且新增了__int64 (64位整型)、Decimal(96位十进制数)、String*(字符串类型)和Object*(对象类型)等类型,表1-1列出它们各自数据类型。


  须要注意的是,String和Object在定义一个变量时,注意要有星号("*"),但这个变量不是指针变量,这与标准C++的含义是不同的。例如上面的代码能够改成:
 

#using
 using namespace System;
 int main(void)
 {
 String* hello = S"Hello World";
 Console::WriteLine(hello);
 return 0;
 }


(3) 新增三个托管C++类型:__gc class、__value class和__gc interface

  一个__gc类或结构意味着该类或结构的生命周期是由.NET开发平台自动管理及垃圾自动收集,用户没必要自已去调用delete来删除。定义一个__gc类或结构和标准C++基本类似,所不一样的是在class或struct前加上__gc,例以下面的代码:
 

__gc class G

{
 public:
 int k;
 int sum(int);
 };

 G::sum(int i)

{

return i*(i + 1)/2;

}


 int main()
 {
 G * g = new G;
 Console::WriteLine(g->sum(4)); // 结果输出10
 return 0;
 }


  但要注意:

  A. 一个__gc类不能从一个非托管类中继承,且不能包含从它派生的非托管类。但一个__gc类最多能够从一个托管类中继承。

  B. 一个__gc类不能定义成一个友元类或包含一个友元成员函数。所谓友元函数,是用来让外部函数访问类中的私有和保护类型成员。

  C. 一个__gc类不能声明或定义以及重载new或delete操做以及不能包含using等声明。

  __value类是用来使用具备短生命期的小型数据项,它不一样于__gc类。__gc类数据分配在CLR堆中,而__value类对象是在运行栈或称为 NDP(.NET Developer Platform,.NET开发者平台)堆中建立的,从而避免了垃圾回收器不断分配和释放空间而带来的开销。一个__value类能够声明成为一个局部变量、参数和返回值,也可嵌入到一个__gc类中或是做为一个静态变量或在C++堆中分配的变量。例以下面的代码:
 

#using
 using namespace System;
 __value struct V { int i; };
 __gc struct G { V v; }; // 嵌入到__gc类中
V f(V v) { // 定义一个全局函数,其值存储在运行栈中
v.i += 1; // 不影响原来形参v的值
return v; // 返回V结构类型的值
}
int main(void)
 {
 V v1 = {10}; // 在运行栈中声明并初始化
V v2 = f(v1); // 调用f函数,此时v1中的i为10,而v2中的i为11
 G *pG = new G; // 为G实例分配堆空间
pG->v = v1; // pG的v中的i为10
 pG->v.i += v2.i; // pG的v中的i为10+11=21
 Console::WriteLine(v1.i); // 输出结果为10
 Console::WriteLine(v2.i); // 输出结果为11
 Console::WriteLine(pG->v.i); // 输出结果为21
 return 0;
 }

 

实例应用

使用托管C++粘合C#和C++代码(一)点击打开连接

使用托管C++粘合C#和C++代码(二)点击打开连接

 

Reference:http://www.cppblog.com/yefuhai/archive/2008/08/15/58943.html

C++ 托管扩展编程http://msdn.microsoft.com/zh-cn/library/ms384255(v=vs.71).aspx