技术开发 频道

C++/CLI:第一流的CLI语言(3)

【IT168 技术文档】

  混合类型
 
  我们知道,C++支持本机类型-总是如此;C++支持CLI类型-本文正是特别强调这一点;它还支持混合类型-具有CLI成员的本机类型和具有本机成员的CLI类型!请尽管考虑所有你能的可能需求。
 
  注意,谈到Whidbey,混合类型实现还不完整;就我从Brandon,Herb和Ronald发表的材料的理解得知,存在这种相当酷的类型--统一模型,它将在Orcas中实现--你能够在本机C++堆上new/delete CLI类型,而且也能够在CLI堆上gcnew/delete本机类型。但既然这是Whidbey以后的东西,本文不讨论统一模型。

  在我谈论你何时使用混合类型以前,我想向你说明什么是混合类型。如果你理解混合类型,请跳过下面几段。这里引用Brandon Bray的说法:"一种混合类型,或者是本机类ref类(需要有对象成员),或者是通过声明或继承被分配在垃圾回收堆或本机堆上的。"因此如果你有一个托管类型或者有一个有托管成员的本机类型,你就有了一个混合类型。VC++ Whidbey不直接支持混合类型(统一类型模型是一种Whidbey之后的概念),但是它给我们划定了实现混合类型的条件。让我们开始讨论包含托管成员的本机类型。

ref class R { public: void F(){} //假定 non-trivial ctor/dtor R(){} ~R(){} };
  在我的例子中,设想该托管类型R有一个non-trivial构造器和一个non-trivial析构器。
class Native { private: gcroot<R^> m_ref; public: Native(): m_ref(gcnew R()){} ~Native() { delete m_ref; } void DoF() { m_ref->F(); } };
  既然,我不能在我的类中拥有一个R成员,我使用了gcroot模板类(在gcroot.h中声明,但是你要用"#include vcclr.h"),它包装了System::Runtime::InteropServices::GCHandle结构。它是个象类一样的灵敏指针,它重载了运算符->以返回用作模板参数的托管类型。因此在上面类中,我可以使用m_ref,就好象我已经声明它是R^,而且你能在DoF函数中看到这正在起作用。实际上你可以节省delete,这可以通过使用auto_gcroot(类似于std::auto_ptr,在msclr\auto_gcroot.h文件中声明)代替gcroot来实现。下面是一个更好些的使用auto_gcroot的实现。
class NativeEx { private: msclr::auto_gcroot<R^> m_ref; public: NativeEx() : m_ref(gcnew R()){} void DoF() { m_ref->F(); } };
  下面让我们看相反的情形:一个CLI类的本机成员。
ref class Managed { private: Native* m_nat; public: Managed():m_nat(new Native()){ } ~Managed() { delete m_nat; } !Managed() { delete m_nat; #ifdef _DEBUG throw gcnew Exception("Oh, finalizer got called!"); #endif } void DoF() { m_nat->DoF(); } };
  我不能定义一个Native对象来作为一个ref类成员,因此需要使用一个Native*对象来代替。我在构造器中new该Native对象,然后在析构器和finalizer中delete它。如果你运行该工程的调试版,在执行到finalizer时将抛出一个异常- 因此开发者可以马上添加一个对delete的调用或为他的CLI类型使用栈语义技术。奇怪的是,库开发小组没有建立一个gcroot的反向实现-但这不是个大问题,我们可以自己写。
template<typename T> ref class nativeroot { T* m_t; public: nativeroot():m_t(new T){} nativeroot(T* t):m_t(t){} T* operator->() { return m_t; } protected: ~nativeroot() { delete m_t; } !nativeroot() { delete m_t; #ifdef _DEBUG throw gcnew Exception("Uh oh, finalizer got called!"); #endif } };
  这仅是个相当简单的灵敏指针实现,就象一个负责本机对象分配/回收的ref类。不管怎样,借助nativeroot模板类,我们可以如下修改托管类:
ref class ManagedEx { private: nativeroot<Native> m_nat; public: void DoF() { m_nat->DoF(); } };
  好,关于混合类型的最大问题是什么呢?你可能问。最大问题是,现在你能混合使用你的MFC、ATL、WTL、STL代码仓库和.net框架,并用可能的最直接的方式-只需写你的混合模式代码并编译实现!你可以建立在一个DLL库中建立MFC 类,然后建立一个.NET应用程序来调用这个DLL,还需要把.NET类成员添加到你的MFC类(也实现可以相反的情况)。

 

0
相关文章