【问题标题】:Translate code from Delphi to C ++ Builder 10.3将代码从 Delphi 转换为 C++ Builder 10.3
【发布时间】:2020-05-20 10:55:20
【问题描述】:

parsing 有一个库。

我在项目中添加了ALXmlDoc.pas,C++Builder 创建了ALXmlDoc.hppALXmlDoc.pas 第 177,178 行:

property Nodes [const Name: AnsiString]: TALXMLNode read GetNodeByName; default;
property Nodes [const Index: integer]: TALXMLNode read GetNodeByIndex; default;

ALXmlDoc.hpp:

__property TALXMLNode * Nodes [const System :: AnsiString Name] = {read = GetNodeByName / *, default */};
__property TALXMLNode * Nodes [const int Index] = {read = GetNodeByIndex};

我收到关于重复的错误 - 如何解决?


.pas 705 行

property OnParseText: TAlXMLParseTextEvent read FonParseText Write FonParseText; // [added from TXMLDocument]

ALXmlDoc.hpp:

__property _di_TAlXMLParseTextEvent OnParseText = {read = FonParseText, write = FonParseText};
__interface TAlXMLParseTextEvent: public System :: IInterface
{
    virtual void __fastcall Invoke (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str) = 0;
};
     
private:
    _di_TAlXMLParseTextEvent FonParseText;
protected:
    void __fastcall DoParseText (const System :: AnsiString Path, const System :: AnsiString Str);

在我的Unit1.h

void __fastcall OnParseText (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str);

在我的Unit1.cpp

void __fastcall TForm1 :: OnParseText (System :: TObject * Sender, const System :: AnsiString Path, const System :: AnsiString Str)
{
    ShowMessage(Str); 
}
// ------------------------------------------------ ---------------------------
void __fastcall TForm1 :: Button1Click (TObject * Sender)
{
    TALXMLDocument * aXMLDocument = new TALXMLDocument ("root");
    aXMLDocument-> OnParseText = OnParseText;
}

我收到一个错误:

[bcc32 错误] Unit1.cpp (30): E2235 成员函数必须被调用或者它的地址被占用

如何声明事件?

【问题讨论】:

    标签: delphi c++builder


    【解决方案1】:

    在 C++ 中,数组属性不能仅在其索引类型上重载。因此,您将不得不重命名其中一个有问题的属性,没有其他选择。然后我建议你向库作者提交一份报告,要求使库对 C++ 用户更友好。


    在 Delphi 代码中,TAlXMLParseTextEvent 是对 anonymous method 的引用:

    TAlXMLParseTextEvent = reference to procedure (Sender: TObject; const Path, Str: AnsiString);
    

    这就是为什么它在 C++ 端被转换为 __interface 的原因(因为匿名方法实际上是使用接口在幕后实现的)。 Delphi 风格的匿名方法需要在 C++ 中进行额外处理,如 Embarcadero 的 DocWiki 中所述:

    How to Handle Delphi Anonymous Methods in C++

    实际上,Delphi 通过实现Invoke(...) 方法的接口实现匿名方法类型(也称为方法引用)。

    因此,在 Delphi 中采用方法引用参数的方法作为采用接口的方法公开给 C++。

    因此,您的 C++ 代码将需要执行更多类似的操作:

    struct TParseTextMethod
    {
        void operator()(TObject *Sender, const AnsiString Path, const AnsiString Str)
        {
            ShowMessage(Str); 
        }
    };
    //------------------------------------------------ ---------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
    
        // the TMethodRef functor is defined in the documentation,
        // you can copy/paste it as-is into your code...
        typedef TMethodRef<TAlXMLParseTextEvent,
                         TParseTextMethod,
                         void,
                         TObject *Sender,
                         const AnsiString,
                         const AnsiString> MyMethRef;
    
        aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new MyMethRef(TParseTextMethod()));
    }
    

    或者,您可以通过不使用 TMethodRef 包装器来进一步简化函子的使用(请参阅 Inheritance and InterfacesImplementing Interfaces):

    class TParseTextMethod : public TCppInterfacedObject<TAlXMLParseTextEvent>
    {
    public:
        TParseTextMethod() {}
        INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
    
        void __fastcall Invoke(TObject *Sender, const AnsiString Path, const AnsiString Str)
        {
            ShowMessage(Str); 
        }
    };
    //------------------------------------------------ ---------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
    
        aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new TParseTextMethod());
    }
    

    或者,如果你想继续使用你的 OnParseText() 方法,那么你必须将它包装在一个仿函数中,例如:

    void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
    {
        ShowMessage(Str); 
    }
    //------------------------------------------------ ---------------------------
    typedef void __fastcall (__closure *TAlXMLParseTextMethod)(TObject *Sender, const AnsiString Path, const AnsiString Str);
    
    struct TParseTextMethod
    {
        TAlXMLParseTextMethod Method;
    
        TParseTextMethod(TAlXMLParseTextMethod aMethod) : Method(aMethod) {}
    
        void operator()(TObject *Sender, const AnsiString Path, const AnsiString Str)
        {
            Method(Sender, Path, Str);
        }
    };
    //------------------------------------------------ ---------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
    
        typedef TMethodRef<TAlXMLParseTextEvent,
                         TParseTextMethod,
                         void,
                         TObject *Sender,
                         const AnsiString,
                         const AnsiString> MyMethRef;
    
        aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new MyMethRef(TParseTextMethod(&OnParseText)));
    }
    

    或者:

    void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
    {
        ShowMessage(Str); 
    }
    //------------------------------------------------ ---------------------------
    typedef void __fastcall (__closure *TAlXMLParseTextMethod)(TObject *Sender, const AnsiString Path, const AnsiString Str);
    
    class TParseTextMethod : public TCppInterfacedObject<TAlXMLParseTextEvent>
    {
    public:
        TAlXMLParseTextMethod Method;
    
        TParseTextMethod(TAlXMLParseTextMethod aMethod) : Method(aMethod) {}
        INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
    
        void __fastcall Invoke(TObject *Sender, const AnsiString Path, const AnsiString Str)
        {
            Method(Sender, Path, Str);
        }
    };
    //------------------------------------------------ ---------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
    
        aXMLDocument->OnParseText = _di_TAlXMLParseTextEvent(new TParseTextMethod(&OnParseText));
    }
    

    或者,如果您使用Clang-based compilers 之一,那么您可以使用C++ style lambda 代替仿函数:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
        aXMLDocument->OnParseText = [](TObject*, const AnsiString, const AnsiString Str) {
            ShowMessage(Str);
        };
    }
    

    或者:

    void __fastcall TForm1::OnParseText(TObject *Sender, const AnsiString Path, const AnsiString Str)
    {
        ShowMessage(Str); 
    }
    //------------------------------------------------ ---------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TALXMLDocument *aXMLDocument = new TALXMLDocument("root");
        aXMLDocument->OnParseText = [this](TObject *Sender, const AnsiString Path, const AnsiString Str) {
            OnParseText(Sender, Path, Str);
        };
    }
    

    【讨论】:

    猜你喜欢
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2012-05-04
    相关资源
    最近更新 更多