如何在C ++ Builder

时间:2017-08-30 17:58:29

标签: delphi interface c++builder

此问题中接受的答案显示了如何在Delphi中检查和使用VCL派生对象上的接口。

How to use Interface with VCL Classes - Part 2

procedure Test;
var
  O1: TSomeThing;
  Intf: ISomething;
begin
  O1 := TSomeThing.Create(nil);

  if Supports(O1, ISomething, Intf) then
  begin
    Intf.DoSomething;
  end;

基本上,我想在C ++ Builder中做同样的事情,但还没有弄清楚如何使用C ++中的“Supports”。

在使用VCL派生类时,尝试使用<dynamic_cast>在编译时失败...

TSomeThing * O1;
ISomething *i = dynamic_cast<ISomething*>(O1);  // Error: Can't cast

建议的Inheritance and Interfaces文章提及TObject::GetInterface(),但当我尝试时,我收到错误“纯虚函数称为”。

_di_IFoo mc;

if (this->GetInterface(mc)) ... 

更新:首先,我添加接口的对象是现有的VCL控件,因此不是从TInterfacedObject派生的。

第二 - 没有涉及COM - 我希望! Interfaces的使用纯粹是为了让我使用接口的概念来进行多重继承,而VCL组件是C ++ Builder(至少在2010年)不支持的。

所以我的界面看起来像这样(注意没有__addref/__release等......):

 __interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IMyInterface : public IInterface
 {
 public:
     virtual UTF8String getHello() = 0;
 };

我的对象看起来像这样

class TMyPanel: public TPanel, IMyInterface
{
    ...
public:
    UTF8String getHello() { return "Hello from a TMyPanel";}
    ...
};

class TMyLabel: public TLabel, IMyInterface
{
    ...
public:
    UTF8String getHello() { return "Hello from a TMyLabel";}
    ...
};

这很简单,并且如Embarcadero接口文档中所述。

但是,如何判断特定TObject是否支持IMyInterface ???

以下模板功能基于TObject.GetInterfaceEntry()的{​​{1}}为我执行此操作:

system.pas

我们这样使用它:

template<typename T>
T* getInterface(TObject *obj)
{
    T *intf = NULL;

    PInterfaceEntry interfaceEntry = obj->GetInterfaceEntry(__uuidof(T) );
    if (interfaceEntry && interfaceEntry->IOffset != 0)
    {
        intf = (T*)(((char *)obj) + interfaceEntry->IOffset);
    }

    return intf;
}

请告诉我是否有比这更好的方法,因为VTable / Pointer探险让我的牙齿发痒......

1 个答案:

答案 0 :(得分:4)

你在C ++中使用与在Delphi中相同的方式 - 通过Sysutils::Supports()函数。

当我尝试时,这对我有用:

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    void __fastcall FormClick(TObject *Sender);
private:    // User declarations
    TPanel *p;
    TLabel *l;
    void Test();
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm7 *Form1;
//---------------------------------------------------------------------------
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IMyInterface : public IInterface
{
public:
    virtual UTF8String getHello() = 0;
};

#if !defined(INTFOBJECT_IMPL_IUNKNOWN)
#define INTFOBJECT_IMPL_IUNKNOWN(BASE) \
    ULONG   __stdcall AddRef() { return BASE::_AddRef();} \
    ULONG   __stdcall Release(){ return BASE::_Release();} \
    HRESULT __stdcall QueryInterface(REFIID iid, void** p){ return BASE::QueryInterface(iid, p);} 
#endif

class TMyPanel : public TPanel, public IMyInterface
{
    INTFOBJECT_IMPL_IUNKNOWN(TPanel)
public:
    __fastcall TMyPanel(TComponent *Owner) : TPanel(Owner) {}
    UTF8String getHello() { return "Hello from a TMyPanel"; }
};

class TMyLabel : public TLabel, public IMyInterface
{
    INTFOBJECT_IMPL_IUNKNOWN(TLabel)
public:
    __fastcall TMyLabel(TComponent *Owner) : TLabel(Owner) {}
    UTF8String getHello() { return "Hello from a TMyLabel"; }
};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    p = new TMyPanel(this);
    p->Parent = this;

    l = new TMyLabel(this);
    l->Parent = p;
    l->Caption = L"Test";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClick(TObject *Sender)
{
    Test();
}
//---------------------------------------------------------------------------
void TForm1::Test()
{
    DelphiInterface<IMyInterface> Intf;

    if (Supports(p, __uuidof(IMyInterface), (void*)&Intf))
    {
        UTF8String s = Intf->getHello();
        ShowMessage(s);
        Intf.Release();
}

    if (Supports(l, __uuidof(IMyInterface), (void*)&Intf))
    {
        UTF8String s = Intf->getHello();
        ShowMessage(s);
        Intf.Release();
    }
}
//---------------------------------------------------------------------------