C++ Builder中实现对Delphi匿名函数的支持

好吧,C++里没有匿名函数,看由Pas生成的HPP文件,你会发现它要你实现一个Interface,好在C++的类型声明是随时随地可以进行的,所以对应的实现步骤如下:

1、声明一个类,继承自TCppInterfacedObject<匿名函数类型>以实现匿名函数对应的接口,你愿意写成interface也无所谓,在C++中,struct和class实际上并没啥本质的区别,而interface只是struct的一个别名而已。

 class TMyHandler:public TCppInterfacedObject<TMyAnEvent>
  {
  public:
    void __fastcall Invoke(...你的匿名函数参数)
    {
    你的匿名函数实现代码
    }
  }

在这里不要指望象Delphi的匿名函数一样直接访问局部变量,C++的类受C++限制。

  2、在需要匿名函数的地方,new 一个你的类的实例,这个实例不需要你去释放,它是一个智能指针,然后就OK了。
示例如下:
void __fastcall TForm1::Button1Click(TObject *Sender){
class TMyEvent:public TCppInterfacedObject<TQXMLObjectPropFilterEvent>
  {
  public:
    void __fastcall Invoke(TQXMLNode* ASender, System::TObject* AObject, System::UnicodeString APropName, bool &Accept)
    {
    if (APropName=="Enabled")
      Accept=False;
    else
      Accept=True;
    }
  };
TQXMLNode *AXML=new TQXMLNode;
AXML->Add("Button1",Button1,False,new TMyEvent);
ShowMessage(AXML->Encode(True,L" ");
delete AXML;
}

是不是感觉上面的代码看着有点乱,好吧,万能的宏出马了:

#define DELPHI_ANON(AType,ATypeName,Code) \
  class ATypeName:public TCppInterfacedObject<AType>\
    {\
    public:\
      void __fastcall Invoke##Code\
    };

上面的代码也就变成了:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
DELPHI_ANON(TQXMLObjectPropFilterEvent,TMyEvent,
  (TQXMLNode* ASender, System::TObject* AObject, System::UnicodeString APropName, bool &Accept)
  {
  if (APropName=="Enabled")
    Accept=False;
  else
    Accept=True;
  }
);
TQXMLNode *AXML=new TQXMLNode;
AXML->Add("Button1",Button1,False,new TMyEvent);
ShowMessage(AXML->Encode(True,L" ");
delete AXML;
}

实际上,一般情况下TMyEvent这个类型也不是我们关心的,我们更关心的是一个变量名,也就引申出下一个版本:

#define DELPHI_ANON(AType,Code,AVar) \
  class AType##AVar:public TCppInterfacedObject<AType>\
  {\
  public:\
    void __fastcall Invoke##Code\
  } *AVar=new AType##AVar

那么上面的代码就会变为:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
DELPHI_ANON(TQXMLObjectPropFilterEvent,TMyEvent,
  (TQXMLNode* ASender, System::TObject* AObject, System::UnicodeString APropName, bool &Accept)
  {
  if (APropName=="Enabled")
    Accept=False;
  else
    Accept=True;
  },ACallback
);
TQXMLNode *AXML=new TQXMLNode;
AXML->Add("Button1",Button1,False,ACallback);
ShowMessage(AXML->Encode(True,L" ");
delete AXML;
}

QString新版已经内置了后一种形式的声明,当然如果有更好的办法,我会毫不犹豫的替换掉,不过目前我暂时没有。如果你有更好的实现办法,欢迎提供建议。我觉得通过STL也许有一定的希望,但我没想出来。也许你知道,不要吝啬你的智慧,告诉我吧。

分享到: