轻松使用C++深入研究.NET委托与事件设计
简介
类型安全机制的实现原本采用C风格的回调函数,而。NET框架引入了委托和事件来代替原来的方式;它们被广泛使用。这里我们尝试用标准的C++来实现类似的功能,这样不仅可以更好的理解这些概念,还可以体验C++的一些有趣的技术。
C#中的委托和事件关键字
首先来看一个简单的c#程序(以下代码略有删节)。所执行程序的输出结果如下所示:
从OB1调用的simpledelegated函数,
string = eventfired!
事件已触发!(Ob1):2002年5月10日星期五下午3点49分46秒事件发生!(Ob1): 1056318417
从Ob2调用了SimpleDelegateFunction,
string =事件已触发!
事件已触发!(Ob2):2002年5月10日星期五下午3点49分46秒事件发生!(Ob2): 1056318417
这一切都源自这样一行代码:DAE . fireprintstring(" event fired!");
在用C++实现这些功能的时候,我模仿了C#的语法,完全按照功能的要求来开发。
命名空间DelegatesAndEvents
{
类DelegatesAndEvents
{
公共委托void PrintString(string s);
公共事件PrintString MyPrintString
public void FirePrintString(string s)
{
if(MyPrintString!= null)MyPrintString;
}
}
类TestDelegatesAndEvents
{
[stat thread]
static void Main(string[]args)
{
DelegatesAndEvents DAE = new DelegatesAndEvents();
my delegates d = new my delegates();
d . Name = " Ob1 ";
dae。MyPrintString+=新DelegatesAndEvents。PrintString(d . SimpleDelegateFunction);
//...更多类似于上面几行的
//的代码...
dae。FirePrintString("事件已触发!");
}
}
class my delegates
{
//...省略“名称”属性...
public void SimpleDelegateFunction(string s)
{
Console。WriteLine("从{0}调用的SimpleDelegateFunction,string={1} ",m_name,s);
}
/...更多方法...
}
c++中的类型安全函数指针
对“老式方法”的批评之一是它们不是类型安全的[1]。下面的代码证明了这一点:
typedef size _ t(* func)(const char *);
void printSize(const char * str){
FUNC f = strlen;
(void)printf(" % s is % LD chars \ n ",str,f(str));
}
void crashAndBurn(const char * str){
FUNC f = reinterpret _ cast < FUNC >(strcat);
f(str);
}
代码可以在[2]中找到。当然,当你使用reinterpret_cast时,你可能会遇到麻烦。如果移除强制转换,C++编译器将报告错误,相对安全的static_cast无法完成强制转换。这个例子也有点像苹果和橘子的比较,因为C#中一切都是对象,reinterpret_cast相当于一个解。下面的C++程序示例将通过使用成员函数的指针来避免使用reinterpret _ cast:
struct object { };
struct Str:public Object {
size _ t Len(const char * Str){
return strlen(Str);
}
char* Cat(char* s1,const char * S2){
return strcat(S1,S2);
}
};
typedef size _ t(Object::* FUNC)(const char *);
void printSize(const char * s){
Str Str;
FUNC f = static _ cast < FUNC >(& Str::Len);
(void) printf("%s是%ld个字符\n ",s,(str。* f)(s));
}
void crash andburn(const char * s){
Str Str;
FUNC f = static _ cast < FUNC >(& Str::Cat);
(字符串。* f)(s);
}
static _ cast运算符会转换Str::Len函数指针,因为Str是从Object派生的,但Str::Cat是类型安全的,不能转换,因为函数签名不匹配。
成员函数指针的工作机制与常规函数指针非常相似;区别(除了更复杂的语法)在于您需要一个用于调用成员函数的类的实例。当然,我们也可以使用-> *运算符,用指向类实例的指针来完成对成员函数的调用。
Str * pStr = new Str();
FUNC f = static _ cast < FUNC >(& Str::Len);
(void) printf("%s是%ld chars\n ",s,(str-> * f)(s));
删除pStr
只要所有类都是从基类对象派生的(就像在C#中一样),就可以使用C++创建类型安全的成员函数指针。
0条评论