В Дельфи есть удобный сервис создания объектов\компонентов из известного метакласса этого объекта\компонента.
В C++ Builder такого сервиса язык С++ не предоставляет (насколько я знаю), даже с учетом его нестандартных расширений Embarcadero. Реализовать недостающий функционал можно используя симбиоз из pas и cpp. Кроме того, надо понимать, что этот подход работает только для чистых Delphi объектов. С++ класс, порожденный от базового Delphi класса, это уже гибрид, который с помощью такого метода создавать небезопасно.
- Создаем модуль паскаля с необходимыми нам сервисами (у меня он называется EsCoreGuiSysUtilities.pas):
unit EsCoreGuiSysUtilities;
/// Special utility stuff that may be implemented only in Delphi Pascal language
///
interface
uses
System.Classes,
FMX.Types,
FMX.TextLayout;
function objectCreate( meta: TClass ) : TObject; overload;
function objectCreate( meta: TComponentClass; owner: TComponent ) : TComponent; overload;
function textLayoutCreate( meta: TTextLayoutClass; const canvas: TCanvas ) : TTextLayout;
implementation
function objectCreate( meta: TClass ) : TObject;
begin
result := meta.Create();
end;
function objectCreate( meta: TComponentClass; owner: TComponent ) : TComponent;
begin
result := meta.Create( owner );
end;
function textLayoutCreate( meta: TTextLayoutClass; const canvas: TCanvas ) : TTextLayout;
begin
result := meta.Create( canvas );
end;
begin
end.
- Включаем исходник на паскале в наш С++ проект. NB! Исходники паскаля компилируются прежде исходников на c\cpp, поэтому к началу работы компилятора С++ у нас уже будет автоматически создан заголовочный файл, соответствующий паскалевскому модулю:
// CodeGear C++Builder
// Copyright (c) 1995, 2013 by Embarcadero Technologies, Inc.
// All rights reserved
// (DO NOT EDIT: machine generated header) 'EsCoreGuiSysUtilities.pas' rev: 25.00 (Windows)
#ifndef EscoreguisysutilitiesHPP
#define EscoreguisysutilitiesHPP
#pragma delphiheader begin
#pragma option push
#pragma option -w- // All warnings off
#pragma option -Vx // Zero-length empty class member
#pragma pack(push,8)
#include <System.hpp> // Pascal unit
#include <SysInit.hpp> // Pascal unit
#include <System.Classes.hpp> // Pascal unit
#include <FMX.Types.hpp> // Pascal unit
#include <FMX.TextLayout.hpp> // Pascal unit
//-- user supplied -----------------------------------------------------------
namespace Escoreguisysutilities
{
//-- type declarations -------------------------------------------------------
//-- var, const, procedure ---------------------------------------------------
extern DELPHI_PACKAGE System::TObject* __fastcall objectCreate(System::TClass meta)/* overload */;
extern DELPHI_PACKAGE System::Classes::TComponent* __fastcall objectCreate(System::Classes::TComponentClass meta, System::Classes::TComponent* owner)/* overload */;
extern DELPHI_PACKAGE Fmx::Textlayout::TTextLayout* __fastcall textLayoutCreate(Fmx::Textlayout::TTextLayoutClass meta, Fmx::Types::TCanvas* const canvas);
} /* namespace Escoreguisysutilities */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ESCOREGUISYSUTILITIES)
using namespace Escoreguisysutilities;
#endif
#pragma pack(pop)
#pragma option pop
#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif // EscoreguisysutilitiesHPP
- Теперь мы можем просто использовать созданный на паскале функционал в С++. Т.к. я это делал для использования в своей библиотеке, в namespace EsUtilities, то соответствующие вызовы библиотеки были перенаправлены в вызовы паскалевского модуля.
в EsUtilities.h:
/// Utilities namespace
///
namespace EsUtilities
{
/// Create Delphi object instance from its metaclass
EKOSF_COREGUI_FUNC TObject* NEW(TMetaClass* mc);
/// Create Delphi component instance from its metaclass
EKOSF_COREGUI_FUNC TComponent* NEW(TComponentClass mc, TComponent* Owner);
/// Create FMX TTextLayout object from its metaclass
EKOSF_COREGUI_FUNC TTextLayout* NEW(TTextLayoutClass tlc, TCanvas* const canvas = 0);
в EsUtilities.cpp:
#include "EsCoreGuiUtilities.h"
#include "EsCoreGuiSysUtilities.hpp"
TObject* EsUtilities::NEW(TMetaClass* mc)
{
ES_ASSERT(mc);
return Escoreguisysutilities::objectCreate(mc);
}
//---------------------------------------------------------------------------
TComponent* EsUtilities::NEW(TComponentClass cc, TComponent* Owner)
{
ES_ASSERT(cc);
return Escoreguisysutilities::objectCreate(cc, Owner);
}
//---------------------------------------------------------------------------
TTextLayout* EsUtilities::NEW(TTextLayoutClass tlc, TCanvas* const canvas /*= 0*/)
{
ES_ASSERT(tlc);
return Escoreguisysutilities::textLayoutCreate(tlc, canvas);
}
//---------------------------------------------------------------------------