Объединение интерфейсов с любым классом (tnx Warfley!)
В недавнем обсуждении на форуме было поднято предложение о возможности добавления COM-интерфейса к любому классу, не наследующему TInterfacedObject. Это обновление позволяет использовать механизм автоматического управления памятью (стиль ARC) и расширяет функциональность разработчиков, работающих с компонентным программированием.
Проблема
До недавнего времени, для добавления COM-интерфейса к классу, необходимо было, чтобы класс наследул TInterfacedObject. Это ограничение не позволяло использовать данный механизм для объектов, которые не могут быть изменены для наследования от TInterfacedObject, например, для третьесторонних библиотек или классов, имеющих сложную иерархию.
Решение
Внедрение обобщенного класса TInterfaced<T> позволяет добавить интерфейс к любому классу, сохраняя при этом возможность использования всех методов и свойств TObject. Это достигается за счет использования обобщений (generics), которые генерируют необходимый код для каждого конкретного класса, к которому добавляется интерфейс.
Пример кода, который реализует данное решение:
Program examplecom;
uses classes;
type
IInterfaced = interface
['{ADEAD83C-06E1-41A5-A40B-C19D06FE8B9F}']
end;
TInterfaced<T:class,constructor> = class(T,IInterfaced)
private
frefcount:integer;
FDestroyCount:integer;
public
function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;
out obj) : longint;winapi;
function _AddRef : longint;winapi;
function _Release : longint;winapi;
destructor destroy;override;
procedure AfterConstruction;override;
procedure BeforeDestruction;override;
class function NewInstance : TObject;override;
end;
// ... Дальше следует реализация методов QueryInterface, _AddRef, _Release и др.
type
TInterfacedStringlist = TInterfaced<TStringlist>;
var
List:IInterfaced;
SList:TStringlist;
begin
List :=TInterfacedStringlist.create;
with list as TInterfacedStringlist do
begin
Add('some text');
writeln(Text);
end;
// ... Код использования объекта с интерфейсом
end.
Альтернативное Решение
Альтернативный подход, предложенный ASerge, заключается в создании обертки для любого объекта, которая предоставляет интерфейс. Этот подход не требует изменения исходного класса и не влечет за собой дублирование кода. Пример такой обертки:
unit uIntfWrapper;
{$mode ObjFPC}{$H+}
interface
function WrapByInterface(SomeObj: TObject; AOwned: Boolean = True): IInterface;
implementation
uses SysUtils, Classes;
type
TIntfWrapper = class(TInterfacedObject, IInterface)
strict private
FObj: TObject;
FOwned: Boolean;
function QueryInterface(constref iid: TGuid; out Obj): LongInt; winapi;
public
constructor Create(AObj: TObject; AOwned: Boolean = True);
destructor Destroy; override;
end;
// ... Реализация класса TIntfWrapper
function WrapByInterface(SomeObj: TObject; AOwned: Boolean): IInterface;
begin
Result := TIntfWrapper.Create(SomeObj, AOwned);
end;
end.
Использование обертки:
{$MODE OBJFPC}
{$APPTYPE CONSOLE}
uses SysUtils, Classes, uIntfWrapper;
var
IList: IInterface;
begin
IList := WrapByInterface(TStringList.Create);
with IList as TStringList do
begin
Add('some text');
Writeln(Text);
end;
Readln;
end.
Заключение
Оба подхода решают проблему добавления интерфейсов к существующим классам, но выбирать между ними следует, исходя из конкретных требований проекта и предпочтений разработчика. Обобщенный класс TInterfaced<T> предоставляет гибкость и возможность использования всех методов TObject, в то время как обертка TIntfWrapper упрощает процесс и не требует изменений в исходном коде.
Объединение интерфейсов с любым классом стало возможным благодаря введению обобщенного класса `TInterfaced`, который позволяет добавить COM-интерфейс к любому объекту, не зависящему от наследования `TInterfacedObject`, что расширяет функциональность д
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.