托管C++、C++/CLI、CLR
1、什么是托管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关键字的类。
2、为什么使用托管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++托管扩展。
在整个Visual Studio开发套件中,微软为了迎合.NET应用程序开发模式的要求,几乎对每个工具都作了或大或小的改进。其中,VB的变革力度应用微软各种软件产品之最。但是太大的变革往往会带来兼容性问题,特别是新版本的VB宣称其只能开发托管的应用程序(也就是.NET应用程序),所以对开发人员来讲,这肯定意味着过去使用VB编写的代码在新版本VB上进行重新构造的难度会很大。VB以前就在版本兼容性方面有着不如人意的历史—— 在VB4、VB5、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框架和缓慢的自动内存管理并不是必要的,传统非托管代码仍然是一些人的首选。
3、什么是CLR
CLR常用简写词语,CLR是公共语言运行时,Common Language Runtime)和Java虚拟机一样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集),并保证应用和底层操作系统之间必要的分离。
4、什么是C++/CLI
http://baike.baidu.com/view/459502.htm
C++/CLI简介http://blog.csdn.net/eric_jo/article/details/4184916
5、托管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 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;
- }
#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;
- }
__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++/CLI、CLR的更多相关文章
- 【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测CLR性能
原文:[原创]构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)-托管资源优化-监测CLR性能 构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测C ...
- 什么是.NET CLI CLR IL JIT GC,它们是如何工作的
参考网址: https://cloud.tencent.com/developer/article/1432891 1:什么是.NET? NET 是 Microsoft 的用以创建 XML Web 服 ...
- “菜”鸟理解.NET Framework(CLI,CLR,CTS,CLS,BCL,FCL)
既然要学.NET,就要先认识认识她,我不喜欢大段大段文字的东西,自己通过理解,画个图,来看看.NET的沉鱼落雁,闭月羞花之容. 最下层蓝色部分是.NET Framework的基础,也是所有应用软件的基 ...
- 简单介绍托管执行和 CLI
目录 CIL 和 ILDASM 查看 myApp.dll 的 CIL 输出 使用 ILSpy 查看 myApp.dll 反编译后的代码 处理器不能直接解释程序集.程序集用的是另一种语言,即公共中间语言 ...
- CLR回收非托管资源
一.非托管资源 在<垃圾回收算法之引用计数算法>.<垃圾回收算法之引用跟踪算法>和<垃圾回收算法之引用跟踪算法>这3篇文章中,我们介绍了垃圾回收的一些基本概念和原理 ...
- 重温CLR(十五) 托管堆和垃圾回收
本章要讨论托管应用程序如何构造新对象,托管堆如何控制这些对象的生存期,以及如何回收这些对象的内存.简单地说,本章要解释clr中的垃圾回收期是如何工作的,还要解释相关的性能问题.另外,本章讨论了如何设计 ...
- CLR via C# 读书笔记-21.托管堆和垃圾回收
前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...
- 跨越语言的障碍:C++/CLI 调用 C#
首先我想投诉一下博客园首页右边栏的广告..最近总是出现很恐怖的整容脸的广告.真的是吓坏了.=.=大家有同感吗? 博客园前一阵子掀起了语言的广泛讨论,事实上语言的争执在整个程序员圈子也没有停止过.以我个 ...
- 用C++/CLI搭建C++和C#之间的桥梁(二)—— 基本语法
托管对象的创建和引用 在前文中我们已经演示过创建一个托管对象,对于如下C#代码: System.Object x = new System.Object(); 其在C++/CLI中的等价代码如下: S ...
- 用C++/CLI搭建C++和C#之间的桥梁
一.简单用法 C#和C++是非常相似的两种语言,然而我们却常常将其用于两种不同的地方,C#得益于其简洁的语法和丰富的类库,常用来构建业务系统.C++则具有底层API的访问能力和拔尖的执行效率,往往用于 ...
随机推荐
- Python学习之条件判断和循环
#coding= utf-8 # 条件判断和循环 # 如果if语句判断是True,就把缩进的两行print语句执行了,否则,什么也不做 age1 = 20 if age1 >= 18: prin ...
- PyMySQL模块的使用
PyMySQL介绍 PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,Python2系列中则使用mysqldb.Django中也可以使用PyMySQL连接MySQL数据库. ...
- Web 项目报错No suitable driver found for jdbc:mysql://localhost:3306/book 的一个解决办法
确认jar包加入到了build path中,然后注意版本是否与数据库相配,还要留意将jar包放入WEB-INF下的lib文件夹中
- 尼姆博弈(Nimm's Game)
题型: 有3堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限,最后取光者得胜. 思路 首先自己想一下,就会发现只要最后剩两堆物品一样多(不为零),第三堆为零,那面对这种局 ...
- ZOJ-1649 Rescue---BFS+优先队列
题目链接: https://vjudge.net/problem/ZOJ-1649 题目大意: 天使的朋友要去救天使,a是天使,r 是朋友,x是卫兵.每走一步需要时间1,打倒卫兵需要另外的时间1,问救 ...
- CWMP开源代码研究——cwmp移植
原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...
- ubuntu安装IBM DB2 Express-C
去 官网 下载DB2对应Linux下的安装包和语言包.
- 一 Django模型层简介(一)
模型 django提供了一个强大的orm(关系映射模型)系统. 模型包含了你要在数据库中创建的字段信息及对数据表的一些操作 使用模型 定义好模型后,要告诉django使用这些模型,你要做的就是在配置文 ...
- angualar2——八大组成
Angular2 模块 理解: Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules. 组件 组件是一个项目主干,一个模块由多个 ...
- Python基础学习(第一周)
Python是一门什么语言 编译型和解释型 通俗来讲,编译型就是一次性把所有程序写的代码都转换成机器可以识别的语言(机器语言),即可执行文件.exe: 解释型就是程序每执行到某一条指令,则会有有个称之 ...