создать новый экземпляр класса по объекту класса

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

создать новый экземпляр класса по объекту класса

Сообщение vkhacker » 27.03.2019 11:20:00

Здравствуйте!
Требуется создать новый экземпляр класса в функции, которая получает в качестве параметра объект того же класса. Сам класс заранее не известен.

Вот пример, который я создал, чтобы было понятней:

Код: Выделить всё
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, а не того класса, который должен.
vkhacker
незнакомец
 
Сообщения: 9
Зарегистрирован: 06.02.2014 09:50:35

Re: создать новый экземпляр класса по объекту класса

Сообщение Дож » 27.03.2019 11:40:39

Это невозможно.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: создать новый экземпляр класса по объекту класса

Сообщение vkhacker » 27.03.2019 11:52:37

Жаль. Придется идти через абстрактные методы похоже...
vkhacker
незнакомец
 
Сообщения: 9
Зарегистрирован: 06.02.2014 09:50:35

Re: создать новый экземпляр класса по объекту класса

Сообщение Дож » 27.03.2019 12: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.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: создать новый экземпляр класса по объекту класса

Сообщение zub » 27.03.2019 13:29:16

вы хотели сказать
>>создать новый экземпляр класса по экземпляру класса

Я не пробовал, но ИМХО все необходимое есть в вмт, за исключением самого конструктора. создание экземпляра это следующие действия:

NewInstance
InitInstance
Create
AfterConstruction

1,2,4 берем из вмт, 3 организуем предварительной регистрацией возможных классов в структуре наподобии tmap - ключ=адрес вмт, данные=адрес конструктора

Но т.к. у вас есть базовый класс - проще обойтись виртуальными конструкторами
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: создать новый экземпляр класса по объекту класса

Сообщение serbod » 28.03.2019 10:38:18

1. Можно передавать в функцию не экземпляр, а тип класса и от него рожать. Пример такого можно посмотреть в TCollection.

2. Можно получить тип класса через метод ClassType() и родить от него.

А зачем вам такое извращение? Может проще изменить подход?
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: создать новый экземпляр класса по объекту класса

Сообщение Ichthyander » 28.03.2019 14:40:09

Не уверен на 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 и подключает его к библиотеки, к примеру, добавив процедуру регистрации класса
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: создать новый экземпляр класса по объекту класса

Сообщение Снег Север » 28.03.2019 15:11:14

Ichthyander писал(а):К примеру, нужно создать экземпляры того объекта, класс которого неизвестен заранее.

По-моему это грубое нарушение самого принципа объектного программирования.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2993
Зарегистрирован: 27.11.2007 16:14:47

Re: создать новый экземпляр класса по объекту класса

Сообщение Ichthyander » 28.03.2019 15:18:01

Снег Север писал(а):
Ichthyander писал(а):К примеру, нужно создать экземпляры того объекта, класс которого неизвестен заранее.

По-моему это грубое нарушение самого принципа объектного программирования.

Не думаю. Это очень удобно именно как объектно-ориентированное программирование. Это даже не хак и не хитрость и не deprecated - вполне нормально использование, пусть и редко используемое, так как такая задача не так часто возникает и достаточно специфична

Добавлено спустя 2 минуты 29 секунд:
Уточню, что "не то чтобы" класс неизвестен. А неизвестна реализация базового класса (то есть какой наследник класса был использован для объекта донора для клона). И указанный путь вполне себе красивое решение и не нарушает никакие принципы )
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: создать новый экземпляр класса по объекту класса

Сообщение alexs » 28.03.2019 15:50:46

виртуальный конструктор + виртуальный метод для копирования значения свойств (аналог 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

Вот часть моего кода
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4053
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: создать новый экземпляр класса по объекту класса

Сообщение DedFrend » 31.03.2019 10:23:11

Не понимаю почему никто не упоминает методы Assign и AssignTo, которые как раз для этого предназначены. Но, конечно, надо потрудится и сделать их реализации для всех классов, которые собираетесь клонировать.
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: создать новый экземпляр класса по объекту класса

Сообщение Лекс Айрин » 31.03.2019 11:13:52

DedFrend, потому что они для этого не предназначены. Я уже попался на это, когда попытался подключить канвас к компоненту. Заодно научился рисовать на экране монитора. Assign позволяет получить доступ к объекту.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: создать новый экземпляр класса по объекту класса

Сообщение DedFrend » 31.03.2019 12:14:20

А я использую, и успешно, правда не слишком широко
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: создать новый экземпляр класса по объекту класса

Сообщение Ichthyander » 02.04.2019 11:46:11

DedFrend писал(а):Не понимаю почему никто не упоминает методы Assign и AssignTo, которые как раз для этого предназначены. Но, конечно, надо потрудится и сделать их реализации для всех классов, которые собираетесь клонировать.

Потому что это не имеет отношения к поставленной задаче. Он не спрашивал как скопировать свойства и поля объекта вновь созданному. Он спрашивал как создать объект заданного класса (неизвестно какого именно на стадии компиляции).
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru