Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.10.10;
Скачать: CL | DM;

Вниз

Как создать функцию возвращающею разные типы?   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.027 c
14-1095927192
REP
2004-09-23 12:13
2004.10.10
Что такое поддержка MPEG4 в TV тюнерах?


1-1095964820
lipskiy
2004-09-23 22:40
2004.10.10
Как изменить иконку в ImageList?


4-1094149104
den.is
2004-09-02 22:18
2004.10.10
вызов Explorer-а с заданным полем Адрес.


3-1094975672
limon_
2004-09-12 11:54
2004.10.10
Index


4-1094549744
Multy
2004-09-07 13:35
2004.10.10
Как просмотреть список запушеных приложений?