Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];

Вниз

Виртуальное клонирование   Найти похожие ветки 

 
JLes ©   (2005-10-31 16:33) [0]

Глубокоуважаемый All!

Есть иерархия классов, в основе которой лежит некоторый класс TMyObject. Есть также TMyList, в котором лежат объекты классов из вышеуказанной иерархии, доступные через Items[idx]: TMyObject. В TMyList имеется также метод, позволяющий копировать часть одного списка в другой.

Вопрос - как эффективнее всего (как с точки зрения выполнения, так и с точки зрения программирования и сопровождения) организовать создание копий объектов TMyObject (и потомков)?


 
Игорь Шевченко ©   (2005-10-31 16:36) [1]


> Вопрос - как эффективнее всего (как с точки зрения выполнения,
>  так и с точки зрения программирования и сопровождения)
> организовать создание копий объектов TMyObject (и потомков)?
>


Написать виртуальный метод Assign, в котором присваивать значения свойств исходного объекта вновь созданному.

Образцов такого рода действий много в исходных кодах VCL.


 
JLes ©   (2005-10-31 17:24) [2]


> Написать виртуальный метод Assign, в котором присваивать
> значения свойств исходного объекта вновь созданному.


Гм. Представим:


procedure TMyList.CopyFragment(idxBegin, idxEnd: integer; Source: TMyList);
var
 src, tmp: TMyObject;
 i: integer;
begin
 for i:=idxBegin to idxEnd do
 begin
   src:=Source.Items[i];
   tmp:=??? // создаем объект класса, совпадающего с классом src
   tmp.Assign(src); // вариант 1 будет работать, если правильно сработает
// предыдущая строчка. Иначе будет неизвестно, Assign какого класса вызывать.
// однако src будет правильного класса

   src.AssignTo(tmp); // вариант2 - будет вызван Assign правильного класса,
// однако это все равно будет работать только в том случае, если tmp
// будет того же класса, что и src.

 end;
end;


Так что все упирается в создание объекта нужного класса, когда носителем информации о классе является сам копируемый объект. Решение в лоб:


if src is TMyObject2 then
 tmp:=TMyObject2.Create
else if src is TMyObject3 then
 tmp:=TMyObject3.Create
...


Assign сам по себе, без корректного создания копии - не решение.


 
reonid ©   (2005-10-31 17:33) [3]

TMyBaseObject = class
 ...
 function Clone: TMyBaseObject; virtual;
end;


 
JLes ©   (2005-10-31 18:27) [4]


> TMyBaseObject = class
>  ...
>  function Clone: TMyBaseObject; virtual;
> end;


Была такая идея. Неприятно то, что ее нужно писать для каждого класса-наследника, хотя везде она реализуется по одному образцу:

Result:=<нужное имя класса вписать>.Create;
Result:=Assign(Self);

Хотяя.....

Если сделать виртуальные конструктор и Assign, но саму функцию Clone - не виртуальной и только в базовом классе...

Ща попробую.


 
Набережных С. ©   (2005-10-31 19:28) [5]

TObject.ClassType плюс приведение к базовому классу ?

type
 TMyObj = class
 end;

procedure TForm1.Button1Click(Sender: TObject);
var
 a, b: TObject;
begin
 a:=TMyObj.Create;
 b:=a.ClassType.Create;
 ShowMessage(a.ClassName);
 ShowMessage(b.ClassName);
 a.Free;
 b.Free;
end;


 
Набережных С. ©   (2005-10-31 19:36) [6]

Типа такого:

type
 TMyObj = class
   procedure Assign(Source: TMyObj);
   function Clone: TMyObj;
 end;

TMyObjClass = class of TMyObj;

procedure TMyObj.Assign(Source: TMyObj);
begin
...
end;

function TMyObj.Clone: TMyObj;
begin
 Result:=TMyObjClass(ClassType).Create;
 Result.Assign(Self);
end;


?


 
Набережных С. ©   (2005-10-31 19:42) [7]

Да, забыл - Assign и конструктор разумеется виртуальные.
Сам я не пробовал, но вроде бы должно получиться.


 
JLes ©   (2005-10-31 20:02) [8]


>  Result:=TMyObjClass(ClassType).Create;


Как раз приведение типа здесь может оказаться нерабочим, если это приведение достанет статическую ссылку на конструктор. Если же это приведение нужно просто для получения таблицы виртуальных методов, то должно сработать.


 
Набережных С. ©   (2005-10-31 20:13) [9]


> JLes ©   (31.10.05 20:02) [8]

см. [7]:

> Assign и конструктор разумеется виртуальные


 
Набережных С. ©   (2005-10-31 20:21) [10]

А для и статических, и виртуальных конструкторов можно попробовать так:

Result:=TMyObj(ClassType.Create);


 
reonid ©   (2005-10-31 20:27) [11]

> Набережных С. ©   (31.10.05 20:21) [10]
> Result:=TMyObj(ClassType.Create);

тогда вызовется конструктор TObject.Create.
Мне кажется, это не совсем то, что нужно...


 
Набережных С. ©   (2005-10-31 20:59) [12]


> reonid ©   (31.10.05 20:27) [11]

Разве? В  [5] вроде вызывается конструктор TMyObj. Почему должно быть иначе при TMyObj(ClassType.Create)?


 
Набережных С. ©   (2005-10-31 21:02) [13]


> reonid ©   (31.10.05 20:27) [11]

Мы ведь так обращаемся к конкретному классу конкретного объекта. Т.е. вызываем конструктор именно того класса, к которому принадлежит данный конкретный экзэмплер объекта. Такого-же класса объект и будет создеан, имхо. Проверять лень, честно говоря:))


 
umbra ©   (2005-10-31 21:06) [14]


type

TMyObjClass = class of TMyObj;

TMyObj = class
  procedure Assign(Source: TMyObj);
  function Clone(src: TMyObjClass): TMyObj;
end;

procedure TMyObj.Assign(Source: TMyObj);
begin
...
end;

function TMyObj.Clone(src: TMyObjClass): TMyObj;
begin
Result:=src.Create;
Result.Assign(Self);
end;



 
Набережных С. ©   (2005-10-31 21:38) [15]


> umbra ©   (31.10.05 21:06) [14]

По условию задачи, имеется массив различных потомков некоего базового класса. В свете этого пример вызова Clone(src: TMyObjClass) можно увидеть?


 
Набережных С. ©   (2005-10-31 21:44) [16]

Ладно, я спать. Что будет, завтра дочитаю:)
Всем доброй ночи.


 
Lamer@fools.ua ©   (2005-10-31 22:30) [17]

>>JLes ©   (31.10.05 17:24) [2]

src:=Source.Items[i];
  tmp:=??? // создаем объект класса, совпадающего с классом src
  tmp.Assign(src); // вариант 1 будет работать, если правильно сработает
// предыдущая строчка. Иначе будет неизвестно, Assign какого класса вызывать.
// однако src будет правильного класса


src:=Source.Items[i];
tmp := TMyObject(src.NewInstance);
try
  tmp.Create(...);
  tmp.Assign(src);
except
  tmp.FreeInstance;
end;


Конструктор Create и метод Assign, как уже писали ранее, должны быть виртуальными.


 
reonid ©   (2005-10-31 23:46) [18]

>Набережных С. ©   (31.10.05 20:21) [10]

ClassType возвращает значение типа TClass.
Ему доступен только интерфейс TObject.

Если нужно вызвать методы своего класса,
нужно снабдить компилятор соответствующей
статической информацией,
т.е. привести TClass к TMyObjectClass.
Тогда для TMyObjectClass(myObj.ClassType)
будет доступен интерфейс класса TMyObject.
Соответственно, чтобы этот интерфейс был актуален
и для классов-потомков TMyObject, он должен иметь
минимум виртуальный конструктор.


 
Набережных С. ©   (2005-11-01 07:17) [19]


> reonid ©   (31.10.05 23:46) [18]

Все-таки вынудили проверить:)
Да, верно, в случае статического конструктора это не проходит.
Зато с виртуальным конструктором, как предлагалось изначально в [6], [7], все отлично работает, даже если Clone - статический.

type
 TMyBase = class
 private
   FID: integer;
 protected
   procedure ShowID;
   function Clone: TMyBase;
 public
   constructor Create; virtual; abstract;
 end;

 TMyBaseClass = class of TMyBase;
 
 TMyObj1 = class(TMyBase)
 public
   constructor Create; override;
 end;

 TMyObj2 = class(TMyBase)
 public
   constructor Create; override;
 end;

 TMyObj3 = class(TMyObj1)
 public
   constructor Create; override;
 end;

{ TMyBase }

function TMyBase.Clone: TMyBase;
begin
 Result:=TMyBaseClass(ClassType).Create;
end;

procedure TMyBase.ShowID;
begin
 ShowMessageFmt("Class: %s; ID: %d", [ClassName, FID]);
end;

{ TMyObj1 }

constructor TMyObj1.Create;
begin
 FID:=1;
end;

{ TMyObj2 }

constructor TMyObj2.Create;
begin
 FID:=2;
end;

{ TMyObj3 }

constructor TMyObj3.Create;
begin
 FID:=3;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
S1, S2, S3: TMyBase;
C1, C2, C3: TMyBase;
begin
 S1:=nil; S2:=nil; S3:=nil;
 C1:=nil; C2:=nil; C3:=nil;
 try
   S1:=TMyObj1.Create;
   S2:=TMyObj2.Create;
   S3:=TMyObj3.Create;
   C1:=S1.Clone;
   C2:=S2.Clone;
   C3:=S3.Clone;
   C1.ShowID;
   C2.ShowID;
   C3.ShowID;
 finally
   S1.Free; S2.Free; S3.Free;
   C1.Free; C2.Free; C3.Free;
 end;
end;


 
Игорь Шевченко ©   (2005-11-01 10:30) [20]

А какой смысл баталии разводить - достаточно посмотреть, как форма загружается из ресурса dfm - там все вроде ясно написано :)


 
Lamer@fools.ua ©   (2005-11-01 10:57) [21]

Обманул немного в [17]

src:=Source.Items[i];
tmp := TMyObject(src.NewInstance);
tmp.Create(...);
try
   tmp.Assign(src);
except
   tmp.Free;
   raise;
end;


 
Набережных С. ©   (2005-11-01 11:42) [22]


> Игорь Шевченко ©   (01.11.05 10:30) [20]

Имхо, в данном случая регистрация класса несколько лишнее, зачем код увеличивать, раз без него можно обойтись? При загрузки формы нет образца для копирования, отсюда и необходимость в регистрации/поиске класса. А здесь оно как бы без надобности.

> Lamer@fools.ua ©   (01.11.05 10:57) [21]

Имхо то же самое, что в [6] и [19], с тем же ограничением -  необходим виртуальный конструктор, только кода на одну строку больше:))

А вообще-то Игорь прав. Автор вопроса давно получил решение и наплевал и на нас, и на ветку, а мы тут распинаемся...Посему я откланиваюсь.


 
JLes ©   (2005-11-02 10:09) [23]


> Автор вопроса давно получил решение
> и наплевал и на нас, и на ветку, а мы тут распинаемся...


Неправда. Просто у меня во вторник тырнета не было.

Для меня ключевым моментом было использование ClassType и приведение его к корневому классу иерархии. После этого все было делом времени.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.013 c
14-1131521835
Pazitron_Brain
2005-11-09 10:37
2005.11.27
Wap форум


2-1131736686
Mozart
2005-11-11 22:18
2005.11.27
Delphi + PostGreSQL


14-1130674520
Очкарик
2005-10-30 15:15
2005.11.27
Зрение за компом


2-1131385242
Toxa_ua
2005-11-07 20:40
2005.11.27
Чтение файла. Помогите пожалуйста. -))


4-1127657412
Ландграф Павел
2005-09-25 18:10
2005.11.27
Реакция окна программы на taskbar





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский