学习C++/CLI

来源:互联网 发布:java程序课程 编辑:程序博客网 时间:2024/05/22 02:04

转自:http://blog.csdn.net/accesine960/article/details/135803

C++/CLI简介如下:

托管的C++(MC++)饱受诟病的一个地方就是语法格式和普通的编程语言差别很大,很多人都评价为: ugly 和  twisted 语法。

因为.net 的基础之一Common Language Infrastructure CLI是提交给了ECMA标准委员会。为了改进现有的MC++ ECMA在 2003年10月份起动了一个新的工作小组,其任务是为ISO标准的C++和CLI之间的交互操作提供一组新的语言扩展。这也就是C++/CLI的由来。

改进前的MC++有如下缺点:

1、 语法格式不雅观,比如很多双下划线的关键字;

2、 托管的C++在和CLI交互是并不能使用全部的功能,比如在C#或者VB.NET中可以使用 for-each 等语法,而MC++不可以;

3、 MC++提供不了一些标准C++的语言特性,比如:C++中的模板,和CLI的内存收集(garbage collection);

4、 非托管的指针和托管的引用指针在语法上都用*表示,容易混淆;

5、 MC++的编译器的效果不好。

现在的C++/CLI也就是Whidbey中的MC++,完全解决了上面的ugly 和 twist的问题。

下面我们来介绍一些特性:

还是从HelloWord 开始吧:

void _tmain()

{

//^ 号是新引进的语法,表示一个handler

String^ str = "Hello World";

    Console::WriteLine(str);

}

上免得 ^str handler就表示指向一个托管对象的引用。

Handler 和 C++中的指针的区别如下:

1、 语法上 用 ^和*区别;

2、 Handler是建立在托管堆上的一个被(CLI)管理的引用,而指针指向一个物理的内存地址;

3、 指针不受垃圾回收器的影响,而handler实际指向的内存地址则收垃圾回收器的管理;

4、 使用指针必须用声明使用delete来释放内存,而handler可以使用也不可以使用;

5、 Handler是类型安全的,每个指向托管对象的handler都对应一个具体的类型,而指针则没有要求,比如可以使用void * 指针;

6、 语法上使用new返回一个指针,而gcnew返回一个handler。

 

请看下面的例子:

void _tmain()

{

    String^ str = gcnew String("Hello World");

    Object^ o1 = gcnew Object();

    Console::WriteLine(str);

}

 

       上例gcnew用来在CLR堆上初始化一个托管对象并返回一个handler。这样的语法可以和指针的声明很清楚的区别开来。

       看一个具体的例子:

using namespace System;

 

interface class IDog

{

    void Bark();(看一个网友评论说是void virtual Bark();)

};

 

ref class Dog : IDog

{

public:

    void Bark()

    {

        Console::WriteLine("汪汪");

    }

};

 

void _tmain()

{

    Dog^ d = gcnew Dog();

    d->Bark();

}



转自:http://blog.csdn.net/luqinghua/article/details/1551418

深入学习C++/CLI

CLI 指的是通用语言结构,一种支持动态组件编程模型的多重结构,在许多情况下,这代表了一个与C++对象模型完全颠倒了的模式,一个时实的软件层,有效的执行了系统,在底层操作系统与程序之间运行,操作底层的设备受到一定限制,操作执行程序中的活动类型及与程序相关联的下部结构得到了支持,反斜杠(/) 代表C++和CLI的捆绑。

  C++/CLI : 它是静态C++对象模型到CLI的动态组件对象编程模型的捆绑,简而言之,它就是你如何用C++在.net中编程。

CLR实时通用语言是CLI的微软版本,它非常适用于Windows操作系统,相似地,Visual C++2005是C++/CLI的实现。

  作为第二个近似的答案,我认为C++/CLI是.NET编程模式与C++的结合,正如以前将模板与C++结合起来产生的泛型编程。所有这种结合中,企业所拥有的C++的投资以及开发人员使用C++的经验将得到保存,而这恰恰是使用C++/CLI进行开发的重要基础。

DOCUMENT

 

CLI对象模型
1.追踪句柄            tracking handle
2.内部指针               interior pointer
3.固定指针               pinning pointer
 
追踪句柄--- 指向“托管堆上一个完整的对象(whole object)”的指针。是会自动更新的指针
内部指针 --- 指向托管堆上“对象所包涵的内部成员”的指针
固定指针 --- 固定托管堆上“对象所包含的数据成员的指针”,使之不能被垃圾收集器控制
 
2.数据成员
(1)实例字段:占据存储位置,表示组件/对象状态,不同对象的实例字段拥有不同的存储位置
(2)静态字段:占据存储位置,表示组件/对象的全局状态,所有对象的静态字段“共享”同一个存储位置
(3)常量字段:编译时常量,必须在声明的同时初始化(内联初始化),默认静态
(4)只读字段:运行时只读,不可以改变,可以在声明的同时进行初始化(只对静态适用),或者在构造器中初始化,并不默认静态
3.成员函数
(1)实例方法,属于对象实例,可以访问实例字段,也可以访问静态字段。
(2)静态方法,属于类型,不可访问实例字段,只能访问静态字段。
4.组件成员:成员函数 + 数据成员的变体
(1)属性:函数变体,实际上是在背后生成了一个私有字段和两个公有的函数
(2)属性(扩展)
privateint Int_Data;
publicproperty int x
         {
                   int get()
                   {
                            return Int_Data;
                   }
                   void set(int value)
                   {
                            Int_Data = value;
                   }
         }
(3)事件:
           (1)委托– CLI托管函数指针类型
              (2)定义一个事件,实际上是在背后定义了一个委托类型的私有字段和三个函数:
                            (1)add_Click    
                            (2)remove_Click
                            (3)raise_Click
(4)事件扩展:
         public ref class Button
         {
                   EventHandler^ handler;
         publicevent EventHandler^ Click
                   {
                            void add(EventHandler^ e)
                            {
                                     Lock<Mutex> I(m);
                                     handler += e;
                            }
                            void remove(EventHandler^ e)
                            {
                                     Lock<Mutex> I(m);
                                     handler -= e;
                            }
                   }
         };
 
托管编程与资源管理:
           资源是软件的主题,使用资源总是难免的,但资源泄露总是可以避免的,C++/CLI 两大类资源,托管内存和非托管资源,托管内存是托管堆上的内存空间,非托管资源是本地堆内存,文件句柄,数据库连接,网络链接,GDI设备句柄……
垃圾收集器只能追踪托管对象的内存使用,而无法知道费托管资源何时不再被使用,内存释放并不会导致非托管资源被释放。如何在内存被释放之前释放非托管资源
Object.Finalize方法。 C++/CLI不允许显式重写
ref class Destruction
{
protected: !Destruction()
         {
                  //实际是在重写System::Object.Finalize();
         }
};
Finalize 会将对象的代龄延长,使无效的对象长时间存在于托管堆中,给托管堆带来内存负担
Finalize 只会为托管资源清理提供了最后一层保障,并不推荐。
System::GC::SuppressFinalize();告知垃圾收集器不需要再调用Finalize从而减轻对象的负担
 
元数据与动态编程
C++/CLI 元数据系统
(1)         动态编程 1 ---- 反射 Reflection
(2)         动态编程 2 ---- 特性 Attributes         
动态程序是指能够在运行时改变自身结构和行为的程序
静态 ---- 编译时,早约束,紧耦合
动态 ---- 运行时,迟约束,松耦合        
ISO-C++ 是一门静态编程语言,只具有非常有限的动态能力,动态堆内存---- 虚函数的动态绑定,有限的类型识别能力----RTTI,获得了极高的效率,却丧失了动态编程所具有的高灵活性
         --DLL动态链接库
         --COM组件         
反射 Reflection动态的发现类型,操作类型,创建类型(查询元数据)
特性 Attributes允许程序定义新的数据类型,从而在运行时动态的感知环境(创建元数据)        
元数据(Metadata) : 是数据的数据,是CLI组件合同的描述载体,组件的平台的粘合剂,CLI                 元数据分为:定义型元数据 –描述代码中定义了什么,引用型元数据 –描述代码中引 用了什么,特性 –扩展定义新的元数据。
 
泛型编程:通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程模式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。它意味着一种新的抽象性质,从本质上来讲,它是数据类型的一组需求条件。泛型编程不是容器编程
 
C++/CLI支持两大泛型机制,三种泛型应用
(1)编译时机制 ---- ISO-C++模版
                   ---- 编译时实例化
                   ---- 基于签名的隐式约束
(2)运行时泛型 ---- CLI泛型
                   ---- 运行时实例化
                   ---- 基于“基类 + 接口”的显式约束。
应用:
(1)         在ISO-C++本地类型上应用模板(编译时泛型)
(2)         在CLI托管类型上应用模板(编译时泛型)
(3)         在CLI托管类型上应用CLI泛型。
(4)        C++/CLI所支持的泛型程序库
(1)         标准模板库 STL
(2)         CLI标准模板库 STL.NET
(3)         CLI泛型库 System::Collections::Generic
eg:
         generic <typename T>
         public ref class Stack
         {
         public: T tem;
                            T Pop()
                            {
                                     return tem;
                            }
                            String^ GetStr()
                            {
                                     //用追踪句柄来调用函数成员
                                     return tem->ToString();
                            }
                            void Push(T t)
                            {}
                            int Size()
                            {
                                     return 0;
                            };
         };
         publicvoid TestEvery()
                   {
                            Stack<System::String^>^ sta = gcnew                                                 Stack<System::String^>();
         }
CLI 泛型机制:
第一轮编译时,编译器只为Stack<T>类型产生泛型版的IL代码与元数据----并进行泛型类型的实例化,T 在中间只充当占位符。
JIT编译时,当JIT编译器第一次遇到Stack<System::String^>时,将String^替换“泛型版”IL代码与元数据中的T----进行泛型类型的实例化。
CLI为所有类型参数为ref class 的泛型类型产生同一份代码,但是如果参数类型为value class ,针对每一个不同的value class ,CLI将产生一份独立的代码。
CLI 泛型机制特点:
(1)         由于CLI泛型的实例化会推迟到JIT编译阶段进行,因此未经实例化的泛型类型会存在于编译生成的程序集中,成为一个类型实体。
(2)         如果实例化泛型类型的参数相同,那么JIT编译器会重复使用该类型,因此CLI泛型可以避免C++ 模板可能导致的代码膨胀问题。
(3)         CLI泛型类型携带有丰富的元数据,因此可以通过反射来获取程序集中的泛型类型的相关信息。
CLI泛型适用于四种对象:
(1)         CLI托管类型(包括引用类型和值类型)
(2)         CLI接口类型
(3)         CLI委托类型
(4)         函数(成员函数,全局函数)
CLI不适用于:
(1)         ISO-C++ 本地类型 ---- 本地类型没有CLI泛型的条件:元数据的信息
(2)         CLI属性,事件,索引器,操作符
A.                 CLI泛型接口:
         generic <typename Item>
         public interface class IList
         {
                   void ListCount();
         };
         generic <typename Item>
         ref class MyList : public IList<Item>
         {
         publicvirtual void ListCount()
                  {
                            Console::WriteLine("Call interface method !");
                   }
};
B.                 CLI泛型委托:
         //delegate
         generic <typename type>
         public delegate void MyDelegate(type ty);
 
         public ref struct MyDeleClass
         {
         public ref class DeleClass
         {
         publicstatic void GetInt(int i)
                   {
                            Console::WriteLine("i is ");
                   }
         publicvoid UserDele()
                   {
                            MyDelegate<int>^ dele = gcnew MyDelegate<int>(&DeleClass::GetInt);
                            dele(200);
                   }
};                           
C.                 CLI泛型函数:
              ref class Megedata
        {              
                generic <typename T>
                void ControType(T t)
                {
                }
        };
        调用泛型函数:
              Megedata^ mana = gcnew Megedata();
         mana->ControType<int>(2);
泛型约束
(1)         类型参数约束:
         A.CLI 泛型采用“基类 + 接口”的方式来实现对类型参数的“显式约束”。
         B.CLI 泛型不支持ISO-C++模板所使用的基于“签名”的“隐式约束”。
         C.虽然获得了编译时类型安全和相关代码清晰,但却丧失了很多灵活性(无法使用静态函数,操        作符、字符、内嵌类型等)
(2) 结束代码示例
         generic <typename T>
         ref class MyCollect
         {
                  T t;
                  public void Add()
                  {};
         };
         T 实现 IComparable 接口
 CLI泛型与C++模板:
         两个根本性的区别:
(1)         C++模板为编译时实例化,CLI泛型为运行时实例化
(2)         C++模板为基于“签名”的隐式约束,CLI泛型为基于“基类 + 接口”的显式约束。
CLI泛型不支持如下C++模板中的机制:
(1)         非参数类型
(2)         缺省参数值
(3)         模板的模板参数
(4)         模板特化及部分特化。
A非参数类型
                  template <class type,int size>
                  public ref class StackInfor
                  {
                           array<type>^ m_stack;
                           int top;
                  public: StackInfor() : top(0)
                            {
                                     m_stack = gcnew array<type>(size);
                            }
                  };
                  //调用StackInfor
                  StackInfor<int,100>^ stack = gcnew StackInfor<int,100>();
                   B.缺省参数值
                  template <class type,int size = 256>
                   public ref class StackInfor
                   {
                            array<type>^ m_stack;
                            int top;
                   public: StackInfor() : top(0)
                            {
                                     m_stack = gcnew array<type>(size);
                            }
                   };
                   //调用StackInfor
                   StackInfor<int>^ stack = gcnew StackInfor<int>();
                   StackInfor<int100>^ stack = gcnew StackInfor<int100>();
                   C.模板的模板参数
                   template<template<class T>class TT,class t>
                   ref class MyClass
                   {
                            TT<t> m_data;
                   };
 
                   template <class t>
                   public ref class Apple
                   {};
 
                   ref class Use
                   {
                   publicvoid Test()
                            {
                                     MyClass<Apple,int> ^m_clas = gcnew MyClass<Apple,int>();
                            }
                   };
                   D.模板的局部特化
                   //-----------
                   template <long B,long E>
                   ref struct Power
                   {
                            literal long value = B * Power<B,E-1>::value;
                   };
                   template <long B>
                   ref struct Power<B,0>
                   {
                            literal long value = 1;
                   };
                   //调用
                   Console::Write(Power<2,10>::value);

0 0
原创粉丝点击