Страница 1 из 1
создать новый экземпляр класса по объекту класса
Добавлено: 27.03.2019 10:20:00
vkhacker
Здравствуйте!
Требуется создать новый экземпляр класса в функции, которая получает в качестве параметра объект того же класса. Сам класс заранее не известен.
Вот пример, который я создал, чтобы было понятней:
Код: Выделить всё
program sample;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
type
{ TSampleAbstractClass }
TSampleAbstractClass = class abstract (TObject)
private
Fparam: string;
public
constructor Create(const param: string);
end;
{ TSampleClass }
TSampleClass = class(TSampleAbstractClass)
private
Fobj: TObject;
public
constructor Create;
destructor Destroy; override;
published
property obj: TObject read Fobj;
end;
var
sample,sample2: TSampleClass;
{ TSampleClass }
constructor TSampleClass.Create;
begin
Fobj := TObject.Create;
inherited Create('test');
end;
destructor TSampleClass.Destroy;
begin
Fobj.Free;
inherited Destroy;
end;
{ TSampleAbstractClass }
constructor TSampleAbstractClass.Create(const param: string);
begin
Fparam := param;
end;
function test(const obj: TSampleAbstractClass): TSampleAbstractClass;
begin
// здесь нужно создать новый объект класса наследника от TSampleAbstractClass
Result := TSampleAbstractClass(obj.ClassType.Create);
end;
begin
sample := TSampleClass.Create;
sample2 := TSampleClass(test(sample));
if not Assigned(sample2.obj) then
WriteLn('sample2.obj is not assigned')
else
WriteLn('sample2.obj is assigned');
sample2.Free;
sample.Free;
ReadLn;
end.
В моем примере вызывается конструктор, как я понял, класса TObject, а не того класса, который должен.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 27.03.2019 10:40:39
Дож
Это невозможно.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 27.03.2019 10:52:37
vkhacker
Жаль. Придется идти через абстрактные методы похоже...
Re: создать новый экземпляр класса по объекту класса
Добавлено: 27.03.2019 11:34:39
Дож
Я подумал чуть по-лучше: если у вас объект-образец является наследником вашего базового класса, и данные из образца в дубликат копировать не нужно, то это можно сделать через виртуальный конструктор:
Код: Выделить всё
{$MODE OBJFPC}
type
TSome = class
constructor CreateSome; virtual;
end;
TSomeClass = class of TSome;
TOther = class(TSome)
constructor CreateSome; override;
end;
constructor TSome.CreateSome;
begin
Writeln('TSome.CreateSome');
end;
constructor TOther.CreateSome;
begin
Writeln('TOther.CreateSome');
end;
function CreateSame(Obj: TSome): TSome;
begin
Result := TSomeClass(Obj.ClassType).CreateSome;
end;
begin
CreateSame(TSome.CreateSome);
CreateSame(TOther.CreateSome);
end.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 27.03.2019 12:29:16
zub
вы хотели сказать
>>создать новый экземпляр класса по экземпляру класса
Я не пробовал, но ИМХО все необходимое есть в вмт, за исключением самого конструктора. создание экземпляра это следующие действия:
NewInstance
InitInstance
Create
AfterConstruction
1,2,4 берем из вмт, 3 организуем предварительной регистрацией возможных классов в структуре наподобии tmap - ключ=адрес вмт, данные=адрес конструктора
Но т.к. у вас есть базовый класс - проще обойтись виртуальными конструкторами
Re: создать новый экземпляр класса по объекту класса
Добавлено: 28.03.2019 09:38:18
serbod
1. Можно передавать в функцию не экземпляр, а тип класса и от него рожать. Пример такого можно посмотреть в TCollection.
2. Можно получить тип класса через метод ClassType() и родить от него.
А зачем вам такое извращение? Может проще изменить подход?
Re: создать новый экземпляр класса по объекту класса
Добавлено: 28.03.2019 13:52:42
Ichthyander
Не уверен на 100%, но попробуйте добавить функцию
класса, которая возвращает класс экземпляра и используйте для этого self. В процедурах и функциях
класса self указывает не на экземпляр, а на класс экземпляра. Добавив Create Вы сможете реализовать задуманное
Код: Выделить всё
{ TSampleAbstractClass }
TSampleAbstractClass = class abstract (TObject)
private
Fparam: string;
public
constructor Create(const param: string);
class function SampleClass: TSampleAbstarctClass;
end;
class function SampleClass: TSampleAbstarctClass;
begin
Result:=self;
end;
... ...
ASample2:=ASample1.SampleClass.Create(param);
Отмечу, что
self это текущий класс объекта, а не базовый класс-родитель TSampleAbstractClass
Добавлено спустя 6 минут 14 секунд:serbod писал(а):А зачем вам такое извращение? Может проще изменить подход?
К примеру, нужно создать экземпляры того объекта, класс которого неизвестен заранее. Более того, класс может переопределить пользователь библиотеки/класса. При этом пользователю библиотеки/класса нет необходимости залезать в реализацию этой библиотеки/класса - он просто добавляет свою реализацию/наследник класса
TSampleAbstractClass и подключает его к библиотеки, к примеру, добавив процедуру регистрации класса
Re: создать новый экземпляр класса по объекту класса
Добавлено: 28.03.2019 14:11:14
Снег Север
Ichthyander писал(а):К примеру, нужно создать экземпляры того объекта, класс которого неизвестен заранее.
По-моему это грубое нарушение самого принципа объектного программирования.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 28.03.2019 14:20:30
Ichthyander
Снег Север писал(а):Ichthyander писал(а):К примеру, нужно создать экземпляры того объекта, класс которого неизвестен заранее.
По-моему это грубое нарушение самого принципа объектного программирования.
Не думаю. Это очень удобно именно как объектно-ориентированное программирование. Это даже не хак и не хитрость и не deprecated - вполне нормально использование, пусть и редко используемое, так как такая задача не так часто возникает и достаточно специфична
Добавлено спустя 2 минуты 29 секунд:Уточню, что "не то чтобы" класс неизвестен. А неизвестна реализация базового класса (то есть какой наследник класса был использован для объекта донора для клона). И указанный путь вполне себе красивое решение и не нарушает никакие принципы )
Re: создать новый экземпляр класса по объекту класса
Добавлено: 28.03.2019 14:50:46
alexs
виртуальный конструктор + виртуальный метод для копирования значения свойств (аналог Assign из TComponent)
Код: Выделить всё
V1:=V.ClassType.Create;
if Assigned(V1) then
begin
if V1 is TSQLCommandAbstract then
begin
TSQLCommandAbstract(V1).Create(nil);
try
TSQLCommandDDL(V1).Assign(V);
finally
Вот часть моего кода
Re: создать новый экземпляр класса по объекту класса
Добавлено: 31.03.2019 09:23:11
DedFrend
Не понимаю почему никто не упоминает методы Assign и AssignTo, которые как раз для этого предназначены. Но, конечно, надо потрудится и сделать их реализации для всех классов, которые собираетесь клонировать.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 31.03.2019 10:13:52
Лекс Айрин
DedFrend, потому что они для этого не предназначены. Я уже попался на это, когда попытался подключить канвас к компоненту. Заодно научился рисовать на экране монитора. Assign позволяет получить доступ к объекту.
Re: создать новый экземпляр класса по объекту класса
Добавлено: 31.03.2019 11:14:20
DedFrend
А я использую, и успешно, правда не слишком широко
Re: создать новый экземпляр класса по объекту класса
Добавлено: 02.04.2019 10:46:11
Ichthyander
DedFrend писал(а):Не понимаю почему никто не упоминает методы Assign и AssignTo, которые как раз для этого предназначены. Но, конечно, надо потрудится и сделать их реализации для всех классов, которые собираетесь клонировать.
Потому что это не имеет отношения к поставленной задаче. Он не спрашивал как скопировать свойства и поля объекта вновь созданному. Он спрашивал как создать объект заданного класса (неизвестно какого именно на стадии компиляции).