您的位置: 旅游网 > 网红

C++-CLI:第一流的CLI语言_a

发布时间:2020-01-16 22:19:34

4. 混合类型

我们知道,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类(也实现可以相反的情况)。

作为一例,设想你有一MFC对话框--它通过一个多行的编辑框接受来自用户的数据-现在,你有一新的要求-显示一个只读编辑框,它将显示当前在该多行编辑框中文本的md5哈希结果。你的队友正在悲叹他们将必须花费几个小时钻研crypto API,而你的上司在担忧你们可能必须要买一个第三方加密库;那正是你在他们面前树立形象的时候,你宣布你将在15分钟内做完这项任务。下面是解决的办法:

添加一个新的编辑框到你的对话框资源中,并且添加相应的DDX变量。选择/clr编译模式并且添加下列代码到你的对话框的头文件中:

#include <msclr\auto_gcroot.h>

using namespace System::Security::Cryptography;

使用auto_gcroot模板来声明一个MD5CryptoServiceProvider成员:

protected:

msclr::auto_gcroot<MD5CryptoServiceProvider^> md5;

在OnInitDialog过程中,gcnew MD5CryptoServiceProvider成员。

md5 = gcnew MD5CryptoServiceProvider();

并且为多行编辑框添加一个EN_CHANGE处理器:

void CXxxxxxDlg::OnEnChangeEdit1()

{

using namespace System;

CString str;

m_mesgedit.GetWindowText(str);

array<Byte>^ data = gcnew array<Byte>(str.GetLength());

for(int i=0; i<str.GetLength(); i++)

data[i] = static_cast<Byte>(str[i]);

array<Byte>^ hash = md5->ComputeHash(data);

CString strhash;

for each(Byte b in hash)

{

str.Format(_T("%2X "),b);

strhash += str;

}

m_md5edit.SetWindowText(strhash);

}

这里使用了混合类型:一个本机Cdialog派生类,该类含有一个MD5CryptoServiceProvider成员(CLI类型)。你可以轻易地试验相反的情况(如早期的代码片断已显示的)——可以建立一个Windows表单应用程序而且可能想利用一个本机类库--这不成问题,使用上面定义的模板nativeroot即可。

一岁宝宝不爱吃饭是什么原因
儿童止咳药含不含防腐剂
治口腔溃疡最好的药
怎么调理小儿脾胃虚弱
猜你会喜欢的
猜你会喜欢的