Форум: "Основная";
Текущий архив: 2003.05.12;
Скачать: [xml.tar.bz2];
ВнизПроблемы с полиморфизмом с ребенком в другом Package Найти похожие ветки
← →
NightDaro (2003-04-28 00:14) [0]Здравствуйте.
Такая проблема:
Рассмотрим классовую иерархию:
-- в модуле Base.Pas --
TClass1 = class(TComponent);
-- в модуле Son.Pas, во внешнем пакете Plugin.bpl --
TClass2 = class (TClass1);
-- в Main.pas, загружается Plugin.bpl,
TForm1.Create:
var obj : TClass1;
lst : TComponentList;
...
obj := TClass1(GetClass("TClass2")).Create(Self);
lst.Add(obj);
(lst[0] as TClass1).CallMethod;
^^^^^^^^^^
В этой строке при выполнении оператор as генерит исключение TInvalidTypeCast. То есть не может преобразовать объект класса TClass2 к типу TClass1.
Просьба прокомментировать эту ситуацию, или предложить другие подходы к решению проблемы (Базовое приложение общается с plugin"ами через полиморфизм, основное приложение и plugin"ы uses Base, а потом - описанное выше).
Спасибо.
← →
Goffman (2003-04-28 06:10) [1]
> obj := TClass1(GetClass("TClass2")).Create(Self);
Наверно правильно будет
obj := TClass1(GetClass("TClass2").Create(Self));
Дело в том, что ты пытаешься привести классовую переменную к объектной.
зы: надеюсь ничего не перепутал
← →
NightDaro (2003-04-28 09:32) [2]Почему тогда в Obj все нормально присваивается?
← →
Goffman (2003-04-28 09:59) [3]Как это нормально присваивается?
Функция GetClass возвращает объект типаclass of TPersistent
Ты его пытаешься привести к классу TClass1, который, грубо говоря, находится в совсем другой иерархической ветке.
Такая попытка неизменно должна привести к AV (что у меня и происходит).
Ты наверное чегой-то не договариваешь.
Если хочешь пришли исходник(bruhno@mail.ru)
← →
REA (2003-04-28 10:39) [4]Класс зарегистрирован?
← →
er (2003-04-28 10:48) [5]Попробуй так:
TClass1Class = class of TClass1;
obj := TClass1Class(GetClass("TClass2").Create(Self));
← →
REA (2003-04-28 10:49) [6]А надо ли вообще приведение типа в данном случае? Компилятор ругается? Я вообще делал списки метаклассов.
← →
er (2003-04-28 11:05) [7]REA © (28.04.03 10:49)
Надо.
По крайней мере, к TComponentClass - поскольку
конструктор с AOwner"ом введён именно там.
← →
NightDaro (2003-04-28 11:27) [8]Sorry, я так и писал с самого начала:
TClass1Class = class of TClass1;
...
obj := TClass1Class(GetClass("TClass2")).Create;
Писать GetClass("...").Create(Self) нельзя, тк Er объяснил. Проблема в том, что операторы is и as потом глючат. Но если написать TClass1(lst[0]).CallMethod, то все будет работать. Вот это и непонятно. В чем тогда отличие работы as и приведения типов?
← →
REA (2003-04-28 11:38) [9]Ну и приводить тогда к TComponentClass.
На то он и plugin чтобы делать некоторую абстракцию.
Упоминание правда имени класса в явном виде тоже непонятно зачем.
Зарегистрировать наверно все-же надо. Иначе GetClass не найдет ничего.
← →
NightDaro (2003-04-28 11:49) [10]Все регистрирую. А в явном виде TClass1 применяю, чтобы с десяток функций через GetInterface не доставать, а потом еще из них список интерфейсов не делать и с каждым объектом хранить.. А теперь представим, что у вас архитектура из 7 ортогональных иерархий plugin"ов и они между собой взаимодействуют..
Короче, у меня все работает через приведение типов. а as - не работает.
← →
REA (2003-04-28 11:53) [11]А as применим к метаклассам?
Я имел ввиду упоминание TClass2 в явном виде, что убирает абстракцию.
← →
NightDaro (2003-04-28 12:01) [12]У меня пакет пассивный - только классы регистрирует. Их список получается через конфигурационный файл, они сортируются там по типам, а потом из них плагины типа Manager набирают себе детей. так что не знаю как можно убрать TClass2.
На счет применимости - не знаю. В Help-е мало слишком написанно, непонятно, а опыта пока нет (Теперь, можно сказать, есть:).
← →
Goffman (2003-04-28 12:05) [13]Оператор as - это и есть оператор приведения типов.
В чем его смысл
1. Если ты сделаешь так:
TForm(lst[0]).Name:="rrr";
то delphi это проглотит.
2.(lst[0] as TForm).Name:="rrr";
-> Invalid typeCast
В чем ошибка, я понять не могу. Я промоделировал у себя твою ситуацию. Все работает нормально, что с as что с прямым приведением типов.
Вот код если интересно
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TClass1 = class(TComponent);
TClass2 = class (TClass1);
TClass1Class = class of TClass1;
var
Form1: TForm1;
implementation
uses Contnrs;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var obj : TClass1;
lst : TComponentList;
begin
lst:=TComponentList.Create;
obj := TClass1Class(GetClass("TClass2")).Create(Self);
lst.Add(obj);
(lst[0] as TClass1).Name:="rrr";
end;
initialization
RegisterClass(TClass1);
RegisterClass(TClass2);
end.
← →
NightDaro (2003-04-28 12:10) [14]:) Спасибо, Goffman, у меня все абсолютно замечательно работало, пока я оставался в рамках одого EXE-шника. Попробуй теперь сделать package, в нем файл Unit2.pas uses Unit1.pas, TClass2=class(TClass1), в нем RegisterClass(TClass2);
Потом: в главном модуле - LoadPackage, потом - все то же самое.
Просьба сообщить, если заработает, значит я какую-нибудь мелочь пропустил..
← →
Goffman (2003-04-28 12:56) [15]Дошло :)
Смотри:
Есть модуль (условно Unit1), в котором объявлен TClass1.
Этот модуль подключается и к основному проекту и к плагину.
В итоге что получается: При загрузке пакета Unit1 будет присутствовать в двух экземплярах. То есть в приложении будет два совершенно разных с точки зрения среды выполнения класса TClass1.
В пакете TClass2 будет наследиком одного TClass1, а в основном модуле ты его приводишь к другому TClass1, отсюда и инвалид.
Что нужно сделать.
Вынести описание TClass1 в отдельный пакет, и скомпилировать приложение и твой плагин с этим пакетом
← →
NightDaro (2003-04-28 20:10) [16]Кошмар. Спасибо, объяснили!
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.05.12;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.006 c