Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Виртуальное клонирование [D6]


Страницы:   1 2

JLes ©   (2005-10-31 16:33:00) 

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

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

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


JLes   (2005-11-02 10:09:00) [1]


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


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

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


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


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

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

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

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

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


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

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

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


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

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


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


> 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;


reonid   (2005-10-31 23:46:00) [6]

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

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

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


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

>> 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, как уже писали ранее, должны быть виртуальными.


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

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


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


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

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


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


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:02:00) [11]


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

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


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


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

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


reonid   (2005-10-31 20:27:00) [13]

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

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


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

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

Result:=TMyObj(ClassType.Create);


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


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

см. [7]:

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


JLes   (2005-10-31 20:02:00) [16]


>  Result:=TMyObjClass(ClassType).Create;


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


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

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


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

Типа такого:

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:28:00) [19]

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;


JLes   (2005-10-31 18:27:00) [20]


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


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

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

Хотяя.....

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

Ща попробую.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо