Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.031 c
3-1095184734
Вано
2004-09-14 21:58
2004.10.10
Проверка структуры таблицы


14-1095671996
icebeerg
2004-09-20 13:19
2004.10.10
Вот сподобился


1-1096231022
Kolan
2004-09-27 00:37
2004.10.10
Визуальные стили (или как их там)


4-1094658891
Davinchi
2004-09-08 19:54
2004.10.10
Не получается отслеживать изменение буфера обмена


14-1095845753
Agent[007]
2004-09-22 13:35
2004.10.10
Паспорт





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский