您现在的位置: 天极网 > 开发频道 > 使用C++深入研究.NET委托与事件
全文

使用C++深入研究.NET委托与事件

2004-06-07 09:42作者:翻译 曾毅出处:论坛责任编辑:方舟
  维护委托集

  在C#中,Delegate和Event关键字成对出现用来创建一列委托,就像上面的第一个例子:

new DelegatesAndEvents.PrintString(d.SimpleDelegateFunction);

  创建一个新的类似于我的C++实现的委托对象:

StrLen_Delegate d(str, &Str::Len);

  MyPrintString对象是一个拥有重载运算符+=的事件,这是用来添加委托的。在C++中我们也可以模仿这个功能来完成类似的工作。C#中的Delegate关键字创建了一个MultiCastDelegate对象(详见[3])。你会注意到我将上面的委托类命名为DelegateT_(尾随的下划线说明这个名字是保留的)。严格地说,名字_DelegateT是为这个程序实现而保留的(__DelegateT也是一样的)因为下划线后跟随着一个大写字母。_delegateT也可以(仅有一个被小写字母尾随其后的下划线),但是我偏向于避免所有的由于前下划线所可能导致的潜在错误(阅读我写的代码的人很可能抓不到我的所有规则)也不愿意采用后划线代替它。保留DelegateT_是因为完成效仿.NET功能的委托类是从多播委托(MultiCastDelegate)类派生来的。

  Delegate对象可以很容易地被存储在标准C++容器中。我将使用list,因为它与.NET的工作机制是最接近的。依据你个人的需要,也可以使用vector或者deque。使用集(set)来提供不论委托被附加入几次,仅仅调用一次的有趣的特性。MultiCastDelegate的第一部分如下所示:

template <typename MF_T, typename ARG1 = VoidType,
typename ARG2 = VoidType>
class MulticastDelegateT : public DelegateT_<MF_T>
{
typedef DelegateT_<MF_T> Delegate;
typedef std::list<Delegate> Delegates_t;
protected:
MulticastDelegateT() {}
public:
MulticastDelegateT(Object& o, const MF_T& mf) :
Delegate(o, mf) {}

MulticastDelegateT& operator+=(const Delegate& d) {
m_delegates.push_back(d);
return *this;
}
private:
Delegates_t m_delegates;
};

  这里使用了list和几个typedef来存储委托集。它需要从DelegateT_派生而来,因为下面我将从MultiCastDelegateT派生出DelegateT作为真正的委托类。

  而后激发所有被存储的委托上的一个C#循环中的事件并调用每一个。因为我使用的是标准容器,使迭代器将很方便:

void operator()(ARG1 v1 = VoidType(),
ARG2 v2 = VoidType()) const {
for (Delegates_t::const_iterator it = m_delegates.begin();
it != m_delegates.end(); ++it)
(it->Target()).Invoke(it->Method(), v1, v2);
}

  即使你很适应标准C++容器,这可能也是你不熟悉的一行代码:只在一个模版类中就可以使用迭代器调用成员函数!对迭代器取反引用,我们可以清楚地看到发生了什么:

const Delegate& d = *it;
d.Invoke(d.Method(), v1, v2);

  如果你对迭代器还不是很适应,你可以指出一个就像数组一样的deque:

for (int i=0; i<m_delegates.size(); i++)
Delegate d = m_delegates[i];

  在这里,你可以为DelegateT_ 类添加下面的模板成员函数:

template <typename ARG1, typename ARG2>
void Invoke_(ARG1 v1 = ARG1(), ARG2 v2 = ARG2()) const {
this->Invoke(m_method, v1, v2);
}

  这样就避免了MultiCastDelegateT::Invoke方法一定要将成员函数指针传递给Object::Invoke:

d.Invoke_(v1, v2);

  尽管如此,这将需要每一个参数都有一个默认构造函数,但事实却不见得如此。并且,由于MultiCastDelegateT是真正的委托基类,看上去并没有太大的必要调用Object::Invoke 路径—即使由于这个原因代码显得更为复杂。(这也会在Visual C++.NET中导致可怕的“内部编译器错误”)。

  实际的委托类现在仅仅是MultiCastDelegateT的一个简单的包装:

template <typename MF_T, typename ARG1 = VoidType,
typename ARG2 = VoidType>
struct DelegateT :
public MulticastDelegateT<MF_T, ARG1, ARG2>
{
DelegateT(Object& o, const MF_T& mf) :
MulticastDelegateT<MF_T, ARG1, ARG2>(o, mf) {}
DelegateT() {}
typedef DelegateT<MF_T, ARG1, ARG2> Event;
};

  它的主要功能是提供事件typedef。

  将他们集成起来

  现在你可以用C++编写实现C#例子当中的DelegatesAndEvents类了:

class DelegatesAndEvents
{
// C#: public delegate void PrintString(string s);
typedef DelegateT<Object::void1_T<std::string>::mf_t,
std::string> PrintString_;
public:
template <typename OBJECT>
static PrintString_ PrintString(OBJECT& o,
void (OBJECT::*mf)(std::string)) {
return PrintString_(o,
static_cast<Object::void1_T<std::string>::mf_t>(mf));
}

// C#: public event PrintString MyPrintString;

PrintString_::Event MyPrintString;
void FirePrintString(std::string s) {
MyPrintString(s);
}
};

  这样的语法看上去着实令人恐怖,如果你愿意,可以用一些灵巧的宏来简化它。但最近宏的名声不太好,并且我们进行的这个主题关键是要了解细节。无论怎样,你都应当感谢C#编译器为你做的工作。

  第一行代码创建一个成员函数指针私有的typedef,名称为PrintString_。参数类型std::string需要列两次,这太糟了,但是这正是由于Visual C++不支持局部模版特化造成的。static方法为创建你自己的类型的委托提供了一个方便的方法,允许你这样来写你的代码:

DelegatesAndEvents::PrintString_
myDelegate = DelegatesAndEvents::PrintString(d,&MyDelegates::SimpleDelegateFunction);

  这与上面的C#代码是类似的。

  而后,我们使用来自DelegateT_的Event typedef创建事件。请注意这一系列的typedef是如何允许C++代码至少是有C#代码一些类似之处的。最后,有一个方法触发事件,这与C#尤其相同。(由于你采用的是标准容器,所以不必担心NULL列表。)

  使用委托和事件的客户端的代码就很明了了,而且也很类似于C#代码(同样这些代码也是略有缩减的):

struct MyDelegates : public ObjectT<MyDelegates>
{
// ... Name omitted...
void SimpleDelegateFunction(std::string s)
{
printf("SimpleDelegateFunction called from %s,
string=%s\n", m_name.c_str(), s.c_str());
}

// ... more methods ...
};

void CppStyle()
{
DelegatesAndEvents dae;
MyDelegates d;
d.Name() = "Obj1";
dae.MyPrintString += DelegatesAndEvents::PrintString
(d, &MyDelegates::SimpleDelegateFunction);
// ... more code similar to the above few lines ...
dae.FirePrintString("Event fired!");
}

  请注意MultiCastDelegateT::operator+=是如何被调用来为委托列表添加每一个由静态方法DelegatesAndEvents::PrintString返回的委托的。

共5页。 9 7 1 2 3 4 5 8 :

软件资讯·软件下载尽在天极软件

相关搜索:
关注此文读者还看过
热门关注
特别推荐
网友关注
软件下载
娱乐下载
驱动下载
文章排行
本周
本月
最近更新
关于我们|About us|网站律师|天极服务|电子杂志|RSS订阅|加入我们|网站地图
TMG
Copyright (C) 1999-2009 Chinabyte.com, All Rights Reserved 版权所有 天极网络
商务联系、网站内容、合作建议:010-82657868
版权声明 在线提交意见反馈 渝ICP证B2-20030003号
经营性网站备案信息 网警备案 中国网站排名
天极传媒:天极网|比特网|IT专家网|IT商网|52PK游戏网|IT分众