此问题中接受的答案显示了如何在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探险让我的牙齿发痒......
答案 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();
}
}
//---------------------------------------------------------------------------