Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как избавиться от вариантов в полиморфизме? 
V
    Опции темы
Koster
Дата 3.6.2008, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 2.6.2008

Репутация: нет
Всего: нет



В общем тема сложная для обьяснения. У меня есть два класса:
Код

TBase=class
  ...
  function find(i:integer):integer;
end;

и
TFloat=class(TBase)
  ...
end;


задача состоит в том как надо извратиться чтобы можна было выполнить данный код:

Код

a:TBase;
....
a:=TFloat.Create;
a.find(5.7); // параметр - вещественное число.


В классе TFloat не должно быть описания метода find полностью, т.е. основа (сам поисковый цыкл) должен остаться в классе TBase, чтобы можна было создавать другие типы на основе TBase и использовать его метод find.

Я реализовал это таким образом:
Код

TBase=class
  ...
  private
  function VarToPointer(AValue:variant):pointer;virtual;abstract; \\ создает указатель нужного типа присваивает ему значение и возвращает его.
  public
  function find(AValue:variant):integer;
end;
implementation
  function TBase.find;
  var
     ...
     p :pointer;
  begin
     p:=VarToPointer(AValue);
     ... \\сортировка безтиповых указателей через абстрактный метод cmp сравнивающий два безтиповых указателя в зависимости от потомка
  end;

TFloat=class
   ...
   private
   function VarToPointer(AValue:variant):pointer;override;
end;
implementation
function TFloat.VarToPointer;
var
  p :^double;
begin
  new(p);
  p^:=variant;
  result:=p;
end;


В общем это работает, НО тут используется тип variant, который не может хранить указатель, да к тому же усложняет поиск ошибок связанных с несовместимостью типов. Мне хотелось бы узнать как это можна написать без вариантов?

Это сообщение отредактировал(а) Alexeis - 3.6.2008, 09:24
PM MAIL   Вверх
Felan
Дата 3.6.2008, 07:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Сделай перегрузку в базовом классе... а вообще-то, фигню ты придумал. Может оп другому как-то это на классы разбить?
ЗЫЖ Public, Published и Protected  члены и так доступны в наследниках. Так что для их вызыва из потомка вообще ничего делать не надо.


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
ama_kid
Дата 3.6.2008, 08:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 15
Всего: 95



Цитата(Koster @  3.6.2008,  00:50 Найти цитируемый пост)
Мне хотелось бы узнать как это можна написать без вариантов?
Если я правильно понял вопрос, то я присоединяюсь к совету Felan. Что мешает использовать перегруженные (overload) функции? Создай свою функцию на каждый необходимый тебе тип в классе TBase:
Код
type
TBase=class
 function find(i:integer):integer; overload;
 function find(r:real):real; overload;
end;

TFloat=class(TBase)
end;

TInt=class(TBase)
end;

{ TBase }

function TBase.find(i: integer): integer;
begin
 Result:=1;
end;

function TBase.find(r: real): real;
begin
 Result:=2.1;
end;
...

procedure TForm1.Button1Click(Sender: TObject);
var
 a:TBase;
begin
 a:=TFloat.Create;
 ShowMessage(FloatToStr(a.find(4.2)));
 ShowMessage(FloatToStr(a.find(3)));
end;




--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
pseud
Дата 3.6.2008, 09:30 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



а что мешает в базовом классе оперировать с double
ведь в переменную double не составит труда передать Integer
а при необходимости доделки метода - переопределять его в потомке и дописывать юзая метод предка через inherited
Код

interface

type
  TBase = class
  public
    function Find(AValue: Double): Integer; virtual;
  end;

type
  TFloat = class(TBase)
  public
    function Find(AValue: Double): Integer; override;
  end;

implementation

{ TBase }

function TBase.Find(AValue: Double): Integer;
begin
  Result := 1;
end;

{ TFloat }

function TFloat.Find(AValue: Double): Integer;
begin
  if AValue = 123456 then
  begin
    //...
  end;

  Result := inherited Find(AValue);

  if Result = 654321 then
  begin
    //...
  end;
end;


Это сообщение отредактировал(а) pseud - 3.6.2008, 09:30


--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
Koster
Дата 3.6.2008, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 2.6.2008

Репутация: нет
Всего: нет



Начну по порядку.
Цитата

Что мешает использовать перегруженные (overload) функции?

Мешает то что заранее неизвестно какого типа будет передаваться элемент. Задача состоит в том чтобы можна было добавлять новые классы с новыми типами не меняя базовый. А типы могут быть любыми, вплоть до других классов. Перебрать их всех невозможно.

Цитата

а что мешает в базовом классе оперировать с double

Думаю с предыдущих строк уже понятно, что типы которые передаются в метод find могут быть не только чисельные, а и сложные. Например string.

Мое решение имеет недостаток в том что variant не может хранить указатели, а значит и сложные структуры данных типа классов. Поэтому хочется узнать как избавиться от variant'ов, если это конечно возможно на Delphi (на что я искренне надеюсь). А если невозможно, тогда может кто то скажет есть ли язык в котором это возможно.



Это сообщение отредактировал(а) Koster - 3.6.2008, 16:55
PM MAIL   Вверх
pseud
Дата 3.6.2008, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



тогда так  smile 
Код


interface

type
  TMyVariant = class
  public
    Value: Variant;
  end;

type
  TBase = class
  public
    function Find(AValue: TMyVariant): Integer; virtual;
  end;

type
  TFloat = class(TBase)
  public
    function Find(AValue: TMyVariant): Integer; override;
  end;

implementation

{ TBase }

function TBase.Find(AValue: TMyVariant): Integer;
begin
  Result := 1;
end;

{ TFloat }

function TFloat.Find(AValue: TMyVariant): Integer;
begin
  if AValue.Value = 123456 then
  begin
    //...
  end;

  Result := inherited Find(AValue);

  if Result = 654321 then
  begin
    //...
  end;
end;

end.



Добавлено через 4 минуты и 21 секунду
========================
или даже так 
Код

interface

type
  TMyVariant = class
  public
    Value: Variant;
  end;

type
  TBase = class
  public
    function Find(AValue: TMyVariant): Integer; virtual;
  end;

type
  TFloat = class(TBase)
  public
    function Find(AValue: Double): Integer; reintroduce;
  end;

implementation

{ TBase }

function TBase.Find(AValue: TMyVariant): Integer;
begin
  {...}
end;

{ TFloat }

function TFloat.Find(AValue: Double): Integer;
var
  v: TMyVariant;
begin
  v := TMyVariant.Create;
  try
    Result := inherited Find(v);
  finally
    v.Free;
  end;
end;

end.



Добавлено через 6 минут и 38 секунд
=========================
хотя, признаюсь, смысловой нагрузки в мною написанном наблюдаю слабо  smile 


--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
pseud
Дата 3.6.2008, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



====================

а, вообще, - поддерживаю ama_kid. overload тебе в руки.
главное объяви эти методы в базовом классе.
а реализацию пиши в каждом отдельном потомке на свой метод.
пример.
Код

interface

type
  TBase = class
  public
    function Find(AValue: Integer): Integer; overload; virtual; abstract;
    function Find(AValue: Double): Integer; overload; virtual; abstract;
    function Find(AValue: String): Integer; overload; virtual; abstract;
    function Find(AValue: Pointer): Integer; overload; virtual; abstract;
  end;

type
  TFloat = class(TBase)
  public
    function Find(AValue: Double): Integer; override;
  end;

type
  TPointer = class(TBase)
  public
    function Find(AValue: Pointer): Integer; override;
  end;

implementation


{ TFloat }

function TFloat.Find(AValue: Double): Integer;
begin
  Result := 0;
end;

{ TPointer }

function TPointer.Find(AValue: Pointer): Integer;
begin
  Result := Find(Self);
end;





--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
Koster
Дата 3.6.2008, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 2.6.2008

Репутация: нет
Всего: нет



overload я понимаю как тут использовать. Это не проблема. Хотелось узнать как можно глубже Delphi. 
Просто, а если исходника класса TBase нет под рукой, тогда как быть?

А можете обьяснить по подробнее про reintroduce. Я не совсем понимаю смысл ее.

Это сообщение отредактировал(а) Koster - 3.6.2008, 19:17
PM MAIL   Вверх
Rohoss
Дата 4.6.2008, 01:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Типо замещает  методы описанные в классе родителе и позволяет менять тип… Что-то вроде overload и override вместе взятых… 


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Felan
Дата 4.6.2008, 07:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Цитата(Koster @  3.6.2008,  18:51 Найти цитируемый пост)
Мешает то что заранее неизвестно какого типа будет передаваться элемент. Задача состоит в том чтобы можна было добавлять новые классы с новыми типами не меняя базовый. А типы могут быть любыми, вплоть до других классов. Перебрать их всех невозможно.

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

Или же можно сделать отдельный класс-менеджер, который выполняет нужные тебе функции с объектами и будет принимать определенный интерфейс (или базовый класс, но тогда надо будет делать наследников, а это не так эффективно) для того, что бы обрабатывать эти объекты. А все твои классы, которые ты хочешь использовать реализуют этот интерфейс (или наследуются от нужного базового класса). Т.о. при создании нового класса, который должен использоваться твоим классом-менеджером нужно просто реализовать интерфейс или перекрыть нужные методы, и базовый класс трогать не надо.


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
pseud
Дата 4.6.2008, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



Цитата(Koster @  3.6.2008,  19:13 Найти цитируемый пост)
если исходника класса TBase нет под рукой, тогда как быть?


тогда переопределяй метод как я уже писал выше reintroduce.
но тогда, используя метод Find в потомках, ты не сможешь использовать его в предыдущей интерпретации.
т.е. твой код все равно не заработает
Koster, 
Код

a:TBase;
....
a:=TFloat.Create;
a.find(5.7); // параметр - вещественное число.




--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
Koster
Дата 4.6.2008, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 2.6.2008

Репутация: нет
Всего: нет



Цитата

твой код все равно не заработает

А можна ли сделать чтобы заработал таки? Или это я слишком много требую?
PM MAIL   Вверх
pseud
Дата 4.6.2008, 09:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



только если так:
Код

a:TBase;
....
a:=TFloat.Create;
TFloat(a).find(5.7); // параметр - вещественное число.



--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
Beltar
Дата 5.6.2008, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 627
Регистрация: 11.1.2006

Репутация: 3
Всего: 7



Цитата

Задача состоит в том чтобы можна было добавлять новые классы с новыми типами не меняя базовый.


Если я правильно понял, тут не ООП ИМХО применять надо, а ф-ии обратного вызова. И ничего наследовать не понадобиться. Как и создавать для каждого типа данных свой класс. Объявляй Find с параметром типа Integer или Pointer и суй него указатель на функцию поиска.

Например так. У меня в одной софтинке есть TreeView и 2 способа сортировки узлов. Объявляю их так. Ни в коем случае не методы формы.

Код

function SortByType(lParam1,lParam2:TTreeNode;  lParamSort:Longint):Integer;stdcall;
function SortByName(lParam1,lParam2:TTreeNode;  lParamSort:Longint):Integer;stdcall;

//И вызываю
case Form5.GetSortType of
  0:TV1.CustomSort(@SortByType,Sort);
  1:TV1.CustomSort(@SortByName,Sort);
end;
//В Sort указываю направление. CustomSort передаст это значение поисковой ф-ии.


Или проще процедурный тип используй.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. smile(с) я, хотя может и нет
Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере.
PM MAIL   Вверх
pseud
Дата 5.6.2008, 09:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Экспёрт Тыдыщ
***


Профиль
Группа: Завсегдатай
Сообщений: 1175
Регистрация: 18.5.2007
Где: Минск, Беларусь

Репутация: 10
Всего: 40



Beltar, помоему ты не правильно понял вопрос.

Цитата(Koster @  3.6.2008,  00:50 Найти цитируемый пост)
задача состоит в том как надо извратиться чтобы можна было выполнить данный код:код Pascal/Delphi1:2:3:4:a:TBase;....a:=TFloat.Create;a.find(5.7); // параметр - вещественное число.


Цитата(Koster @  3.6.2008,  19:13 Найти цитируемый пост)
а если исходника класса TBase нет под рукой, тогда как быть?


т.е. есть класс TBase в каком-то dcu или еще где-то. и надо понасоздавать его потомков с теми же функциями/процедурами но иной реализацией.


--------------------
Испытание чужого терпения можно считать успешным, если оно лопнуло...
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0878 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.