Форум: "Основная";
Текущий архив: 2004.10.10;
Скачать: [xml.tar.bz2];
ВнизКак создать функцию возвращающею разные типы? Найти похожие ветки
← →
Erik1 © (2004-09-23 16:39) [0]Я пробовал создать базовый клас и от него унаследовать 2 потомков в которых переопределить нужную функцию. Но будет ли это работать?
Базовый клас:
TActivItem = class
private
fItem: TObject;
fStart: TSystemTime;
fStatus: TReportStatus;
protected
fID: integer;
fDescription: string;
function GetItem: TObject; dynamic; abstract; //Общая функция
public
constructor Create(Value: TObject);
destructor Destroy; override;
procedure Cancel; dynamic; abstract;
end;
Потомок:
TVisThread = class(TActivItem)
protected
function GetItem: TCustomThread; overload;
public
procedure Cancel; override;
property Item: TCustomThread read GetItem;
end;
Второй потомок:
TVisReport = class(TActivItem)
private
fReportItem: TReportItem;
..........
protected
function GetItem: TBaseReport; overload; //override;
public
property Item: TBaseReport read GetItem;
end;
И использование:
TReportManager = class(TComponent)
......
public
property Items[Index: Integer]: TActivItem read GetItems write SetItems; default;
end;
В Items записываю нужный клас и всегда могу вызывать общие методы определеные в TActivItem. Насколько это правильно?
← →
Defunct © (2004-09-23 16:42) [1]Function F:Variant;
← →
Sandman25 © (2004-09-23 16:45) [2]Вместо
protected
function GetItem: TBaseReport; overload; //override;
Нужно
public
function GetItem: TObject; override;
← →
Erik1 © (2004-09-23 16:47) [3]Пихать класс в Variant? Это чтото не то. Вобщето я хотел устранить [Warning] uRepMgr.pas(55): Method "GetItem" hides virtual method of base type "TActivItem"
← →
Sandman25 © (2004-09-23 16:49) [4]А вообще вместо GetItem: TObject нужно использовать GetItem: TAbstractItem, в котором куча виртуальных методов.
← →
Erik1 © (2004-09-23 16:50) [5]to Sandman25
А накой? Мне то другое надо. Все началась с того, что я захотел одинаково работать с разного типа данным, классы тоже относятся в таком случае к данным. Например у меня есть отчеты и потоки, но методы их завершения у них обшие.
← →
Digitman © (2004-09-23 16:50) [6]
> Defunct © (23.09.04 16:42) [1]
ну и где здесь "разные типы" ? variant как был так и остался ..
> Erik1
возвращай объект базового класса TActiveItem
код, вызвавший Items[], просто производит проверку и приведение типа
if MyResult is TVisThread then with TVisThread(MyResult) do..
else if MyResult is TVisReport then with TVisReport(MyResult) do..
← →
Defunct © (2004-09-23 16:57) [7]> Пихать класс в Variant? Это чтото не то.
Почему не то? прочитайте сами свой вопрос, который звучит "Как создать функцию возвращающею разные типы?"
> Вобщето я хотел устранить [Warning] uRepMgr.pas(55): Method "GetItem" hides virtual method of base type "TActivItem"
зачем это? -
function GetItem: TCustomThread; overload;
это как раз тот случай когда целесообразно использовать директиву reintroduce.TAbstractFamily1 = class
Private
..
Function GetItem:TAbstractClass;virtual;abstract;
..
End;
..
TClass1Family1 = class(TAbstractFamily1)
Function GetItem:TAbstractClass;override;
End;
TAbstractFamily2 = class(TAbstractFamily1)
Function GetItem:TAbstractFamily2; reintroduce; virtual; abstract;
End;
и т.д.
← →
Defunct © (2004-09-23 17:00) [8]> ну и где здесь "разные типы" ? variant как был так и остался ..
дык, Variant тобиш, что надо то и будет.
← →
Sandman25 © (2004-09-23 17:02) [9][5] Erik1 © (23.09.04 16:50)
Понятно. Тогда, действительно, следует оставить TObject.
[7] Defunct © (23.09.04 16:57)
AbstractFamily1: TAbstractFamily1;
Ну и как вызвать нужный GetItem?
← →
Digitman © (2004-09-23 17:02) [10]
> Defunct © (23.09.04 17:00) [8]
вариантный тип - такой же равноправный тип как и все прочие типы
← →
Erik1 © (2004-09-23 17:02) [11]С функцией GetItems особых проблем нет, она возвращает тот клас который в ней записали:
function TReportManager.GetItems(Index: Integer): TActivItem;
begin
Result := fList[Index];
end;
Поскольку у них есть общий предок, то возможно всегда вызвать GetItem и вроде получить правильный обект(TBaseReport, TCustomThread)? Я парав?
Посмотриде внимательно на
function GetItem: TCustomThread; overload; а не override;
← →
Defunct © (2004-09-23 17:08) [12]> AbstractFamily1: TAbstractFamily1;
> Ну и как вызвать нужный GetItem?
Тупо:
AbstractFamily1 := TClass1Family2.Create;
где-то вызывается AbstarctFamily1.GetItem
вернет TAbstractFamily2
← →
Sandman25 © (2004-09-23 17:08) [13][11] Erik1 © (23.09.04 17:02)
Вопрос. Зачем называть GetItem, если можно назвать GetThread?
Как планируется вызывать GetItem? Ведь тип объекта уже явно будет известен, см. пост by Digitman
← →
Sandman25 © (2004-09-23 17:10) [14][12] Defunct © (23.09.04 17:08)
Нет. Будет AbstractError.
← →
Defunct © (2004-09-23 17:16) [15]Erik1 © (23.09.04 17:02) [11]
Я немного поправлю [7], а то там написал не совсем доступно для понимания:TAbstractFamily1 = class
Private
..
Function GetItem:TAbstractFamily1;virtual;abstract;
..
End;
TClass1Family1 = class(TAbstractFamily1)
Function GetItem:TAbstractFamily1;override;
End;
..
TAbstractFamily2 = class(TAbstractFamily1)
Function GetItem:TAbstractFamily2; reintroduce; virtual; abstract;
End;
TClass1Family2 = class(TAbstractFamily2)
Function GetItem:TAbstractFamily2; override;
End;
Object1, Object2 :AbstractFamily1;
Object1 := TClass1Family2.Create;
Object2 := TClass1Family2.Create;
Object1.GetItem вернет TAbstractFamily2;
Object2.GetItem вернет TAbstractFamily1;
← →
Sandman25 © (2004-09-23 17:18) [16]В классе TClass1Family2 метод TAbstractFamily1.GetItem остался абстрактным.
На каком основании TClassFamily.GetItem привязывается к нему? Ведь Вы же явно указали (reintroduce), что методы не имеют ничего общего.
← →
Defunct © (2004-09-23 17:19) [17][15]
Блин, сам запутался в этих единичках и двоечках...
Object1, Object2 : TAbstractFamily1;
Object1 := TClass1Family2.Create;
Object2 := TClass1Family1.Create;
Object1.GetItem вернет TAbstractFamily2;
Object2.GetItem вернет TAbstractFamily1;
← →
Erik1 © (2004-09-23 17:20) [18]to Sandman25
А если у меня добавится новый клас то я сразу должен исходники переписывать? У меня есть TReportManager он неполностью знает с чем работает. Но должен уметь запустить объект и остановить его, кроме того уведомлять о произошедших событиях. Вобщем проектирую я его сейчас, если будут другии идеии то с удовольствием расмотрю. Можно конечно мойти через интерфейсы, этот вариант я еше необдумывал.
← →
Sandman25 © (2004-09-23 17:23) [19]type
TAbstractFamily1 = class
function GetItem: TAbstractFamily1; virtual; abstract;
end;
TClass1Family1 = class(TAbstractFamily1)
function GetItem: TAbstractFamily1; override;
end;
TAbstractFamily2 = class(TAbstractFamily1)
function GetItem: TAbstractFamily2; reintroduce; virtual; abstract;
end;
TClass1Family2 = class(TAbstractFamily2)
function GetItem: TAbstractFamily2; override;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Object2 : TAbstractFamily1;
begin
Object2 := TClass1Family2.Create;
try
Object2.GetItem;
finally
Object2.Free;
end;
end;
{ TClass1Family1 }
function TClass1Family1.GetItem: TAbstractFamily1;
begin
ShowMessage("1");
end;
{ TClass1Family2 }
function TClass1Family2.GetItem: TAbstractFamily2;
begin
ShowMessage("1");
end;
При запуске получаю AbstractError
← →
Erik1 © (2004-09-23 17:27) [20]to Defunct
Понимаеш TVisThread и TVisReport это просто обертка над уже реализоваными классами. И они ничего незнают о том, что надо наследоватся от общего предка. У меня неальный проекет в котором я переписываю Report manager. Так, что твой способ неподойдет.
← →
Sandman25 © (2004-09-23 17:27) [21][18] Erik1 © (23.09.04 17:20)
Как он может запустить объект, если он не знает его тип. Либо через интерфейсы, либо пусть вызывает фабричную процедуру, которая лежит в отдельном модуле и которую надо будет изменять каждый раз.
ИМХО лучше написать оболочку - класс, который будет выполнять роль интерфейса. То есть разные наследники данного класса будут уметь запускать разные объекты, хранящиеся в них же.
← →
Sandman25 © (2004-09-23 17:29) [22]Erik1
Если Вам что-то говорит фраза "паттерн Адаптер", то ИМХО это именно он.
← →
Erik1 © (2004-09-23 17:29) [23]to Sandman25
А для чего я по твоему написал TVisThread и TVisReport они и есть обольчка. :)
← →
Erik1 © (2004-09-23 17:36) [24]to Sandman25
Говорит, чисто теоритически, ни разу неиспользовал. И как это реализавать в конкретном коде незнаю.
← →
Sandman25 © (2004-09-23 17:37) [25][23] Erik1 © (23.09.04 17:29)
Как оболочка они не должны различаться в interface-секции. Только реализация разная. И у них у всех должны быть virtual методы типа DoFinish и т.д.
← →
Defunct © (2004-09-23 17:37) [26]Sandman25 © (23.09.04 17:18) [16]
Да.. пардон забыл о мелочи... ;)
is/as таки нужно применять перед вызовом у меня это было спрятано в статическом приватном методе, как-то и не задумывался..
Erik1 © (23.09.04 17:27) [20]
сорри, за то что не смог помочь, нормально написать пример тоже нужно время..
← →
Sandman25 © (2004-09-23 17:41) [27]TVis = class
protected
procedure DoStart; virtual; abstract;
procedure DoExecute; virtual; abstract;
procedure DoFinish; virtual; abstract;
...
public
procedure Execute;
end;
procedure TVis.Execute;
begin
DoStart;
DoExecute;
DoFinish;
end;
TVisThread = class(TActivItem)
protected
procedure DoStart; override;
procedure DoExecute; override;
procedure DoFinish; override;
end;
...
Manager:
Item[15].Execute;
← →
Erik1 © (2004-09-23 17:49) [28]У меня TVisReport привелигированый класс, он выполняется подругому чем остальные. Для него report manager предоставляет свой тред для его выполнения, а остальным кукиш, приходится самим крутится. Интерфейс для управления хочется иметь общий. Ктоме того все треды от базового пронаследованы. Кащется есть 2 идеии: оставить все как есть и запытать в работе или реорганизовать и переложить обработку тредов на на обертки TVis...
← →
Sandman25 © (2004-09-23 17:52) [29][28] Erik1 © (23.09.04 17:49)
Добавляете метод function RequiresNewThread: Boolean.
Сам Thread или Report не меняется, в этом и есть смысл ввода Адаптеров.
← →
Defunct © (2004-09-23 17:55) [30]Erik1 © (23.09.04 17:49) [28]
> меня TVisReport привелигированый класс, он выполняется подругому чем остальные.
берем пример Sandman25 © (23.09.04 17:41) [27]
изменяем реализацию Execute:
Procedure TReportManager.Execute;
Begin
If Item is TVisReport Then
Begin
PrepareToCreatePriviligedReport;
CreateAnExtendedReportThread;
End Else
If Item is ... Then
Begin
DoStart;
DoExecute;
DoFinish;
End и т.д.
End;
← →
Sandman25 © (2004-09-23 17:58) [31][30] Defunct © (23.09.04 17:55)
Лучше учесть [29] Sandman25 © (23.09.04 17:52)
И написать
Procedure TReportManager.Execute(Item: ...);
Begin
if Item.RequiresNewThread then
begin
...// создаем новый Thread
Item.Execute
...
end
else
Item.Execute
End;
Хотя на самом деле новый поток должен создаваться самим TVisReport в его DoStart :)
← →
Rem (2004-09-23 18:28) [32]1. Варианты не работают с классами.
2. Используйте overloaded/abstract/overriden/ метод с var-параметрами.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.10.10;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.034 c