Модераторы: 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   Вверх
Beltar
Дата 5.6.2008, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата

т.е. есть класс TBase в каком-то dcu или еще где-то


Так где-то или в исходниках? Я вижу, что он показывает код TBase и пишет, что "так реализовал".

Цитата

a:=TFloat.Create;
a.find(5.7)


Т. е. мы немедленно знаем, что у нас в переменной. В этом случае вызов ф-ии обр. вызова наименее трудозатратный способ. Если бы имелся набор переменных TBase и в каждой неизвестный наследник, тогда конечно наследование.

Помоему придется в базовом классе объявлять Find(Pointer); можно пусть даже под др. именами реализовать поиск для простейших типов и строк. Имхо это разумный компромисс. Из разряда той же overload. smile

Кстати, а так ли нужно писать класс, когда можно понаделать миллион перегруженных ф-ий? Какой-то нездоровый подход попахивающий обшарпаным Ц.

Это сообщение отредактировал(а) Beltar - 5.6.2008, 11:18


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


Новичок



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

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



Цитата

Т. е. мы немедленно знаем, что у нас в переменной.


Перед вызовом функции a.find(5.7) для компилятора еще неизвестно какой именно тип параметра передается. В этом то и проблема, потому то и был использован тип variant. А потом в методе find, который является статическим, с помощью абстрактной функции ItemToPointer динамически создается переменная в памяти нужного типа (потомок то знает что там должно быть), записывается туда входной параметр и возвращает в метод find указатель. А find уже сам потом ищет среди таких же нетипизированных указателей нужный элемент. Для сравнения двух указателей используется, опять же абстрактный, метод cmp, который проверяет равны ли значения хранящиеся в этих указателях, и возвращает результат в типе integer.

Цитата

Кстати, а так ли нужно писать класс, когда можно понаделать миллион перегруженных ф-ий? Какой-то нездоровый подход попахивающий обшарпаным Ц.


Миллион перегруженных функций, ИМХО, это некрасиво. Я пока учусь, но приведу пример почему, ИМХО, это некрасиво:
Например, программу пишут несколько человек, один человек делает этот класс и паралельно этот же класс (пока несуществующий, но уже известен его интерфейс) используется другим человеком. Предположим что второму человеку пришлось добавить новый тип для данного класса. Тут есть два варианта:
1. Он берет, и переделывает у себя базовый класс, получается две версии класса. Лично мне кажется это не правильным, да к тому же невозможно если этот класс еще недописан.
2. Он говорит первому программисту чтобы тот добавил новый перегруженный метод. Но в таком случае, если нужно что то подправить, нужно опять же идти к первому программисту и портить ему нервы.
А потом первому программисту пришла в голову невероятно умная мысль, он вспомнил что сортировка "пузырьком" не самая эффективная и начал делать квик сорт. А у него есть миллион перегруженных методов, в которых заново сделана сортировка, и везде надо поменять ее на новую.
Может если первому программисту платят за время работы а не результат, то он даже рад будет. А если нет?

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

Если я не прав в организации работы программистов в группе, подправьте.
PM MAIL   Вверх
Felan
Дата 6.6.2008, 07:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Koster @  6.6.2008,  00:54 Найти цитируемый пост)
Если я не прав в организации работы программистов в группе, подправьте. 

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


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


Опытный
**


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

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



Проблема у тебя в том, что нельзя объявить перекрываемый метод с другим набором параметров. Проще всего сделать его с пойнтером. Если у тебя ищутся сложные структуры данных, то это единственный вариант. С элементарными типами это конечно неудобно и ты не сможешь вызвать a.find(5.7), но элементарных типов-то кот наплакал. LongInt, Cardinal, Extended, String, ну можно и ShortString вспомнить. 3-4 перегруженных ф-ии для них, как тебе советуют, это не проблема. И что-то я не совсем понимаю, кому может понадобиться искать отдельные числа. А строки можно хранить в наследнике TStrings.

У меня еще такой вопрос: А где сами данные-то лежат? Ну допустим все свалены в TList т. е. в простом массиве указателей. Как их различать-то? Так приходим или к контейнеру для строго определенного типа или создаем еще набор классов для хранения данных. smile 
Что вообще делает твоя софтина?

Это сообщение отредактировал(а) Beltar - 6.6.2008, 11:23


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


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


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

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



Koster, 
ты, я думаю, уже успел поработать с такими чудными компонентами дельфи как компоненты для работы с БД.
имеем конструкцию:
Код

  ClientDataSet1.FieldByName('ляляля').AsInteger;

смотрим ее реализацию:
Код

function TField.GetAsInteger: Longint;
begin
  raise AccessError('Integer'); { Do not localize }
end;

ай ай ай, как же так.
а так.
это дело реализовано в TIntegerField:
Код

function TIntegerField.GetAsInteger: Longint;
begin
  if not GetValue(Result) then Result := 0;
end;

А зачем они так сделали? ООП блин.
все объявили в базовом TField.
А реализовали в соответствующих потомках.

Думаю и тебе не стоит чураться такой практики.



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


Новичок



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

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



Цитата

ты, я думаю, уже успел поработать с такими чудными компонентами дельфи как компоненты для работы с БД.


Зря думаешь  smile . 

Цитата

А зачем они так сделали? ООП блин.
все объявили в базовом TField.
А реализовали в соответствующих потомках.


У меня именно так все и реализовано. Для полной ясности приведу полный интерфейс своих классов, если кому то не лень будет разбираться. Это задание было у меня на курсовой по ООП. Я ее сдал с вариантами, никаких претензий небыло. Но я хочу, чисто для себя, понять как это можна реализовать универсальнее.

Вот базовый класс:
Код

type
TBaseArray=class
  private
    FList :TList;

    function cmp(a,b:pointer):integer;virtual;abstract; // -1 - a<b; 0 - a=b;1 - a>b.

    function ConstToPointer(AValue:variant):pointer;virtual;abstract;

    function GetItem(i:integer): variant;virtual;abstract;
    procedure SetItem(i:integer;const Value:variant);virtual;abstract;

    function GetCount:integer;
  public
    function find(AValue:variant):integer;
    procedure sort;
    function ItemToStr(i:integer):string;virtual;abstract;
    constructor Create(ACount:integer);
    destructor Destroy;override;

    property Items[i:integer]:variant read GetItem write SetItem;
    property Count:integer read GetCount;
end;


А вот пример интерфейса потомка:
Код

TIntArray=class(TBaseArray)
  private
    function cmp(a,b:pointer):integer;override;

    function ConstToPointer(AValue:variant):pointer;override;

    function GetItem(i:integer):variant;override;
    procedure SetItem(i:integer;const Value:variant);override;
  public
    function ItemToStr(i:integer):string;override;
end;


Это должно было быть что то на подобие шаблонов в плюсах, естественно гораздо урезаннее по функционалу (пока) и медленнее (так как обрабатывается не компилятором). Но есть и преимущества: можна переинициализовывать одну переменную для разных типов, чего в плюсах делать, как я помню, нельзя.

Опишу ту часть которая интересует больше всего: это метод find. Он в базовом классе реализован вот так:
Код

function TBaseArray.find;
var
  i :integer;
  p :pointer;
begin
  p:=ConstToPointer(AValue);
  for i:=0 to FList.Count-1 do begin
    if cmp(FList.Items[i],p)=0 then begin
      result:=i;
      exit;
    end;
  end;
  Dispose(p);
  result:=-1;
end;


Тут видно что все хранится в TList, т.е. в безтиповых указателях. 
Метод ConstToPointer - абстрактный метод задача которого получить вариант, и перевести его в такой же безтиповый указатель как и остальные элементы TList. Он состоит из таких строк:
Код

function TIntArray.ConstToPointer(AValue: variant): pointer;
var
  p :^integer;
begin
  try
    new(p);
    p^:=AValue;
    result:=p;
  except
    on Exception do begin
      ShowMessage('Несуміні типи');
    end;
  end;
end;

Можно было бы сделать find виртуальным и в каждом потомке его дополнять. Но мне показалось так удобнее.

Еще один абстрактный метод, который играет очень важную роль - это cmp. Он на вход получает 2 указателя, а потом сравнивает их содержимое. Вот его реализация для TIntArray:
Код

function TIntArray.cmp(a, b: pointer): integer;
begin
  result:=0;
  if integer(a^)<integer(b^) then result:=-1;
  if integer(a^)=integer(b^) then result:=0;
  if integer(a^)>integer(b^) then result:=1;
end;

Тут все просто. Остальные методы класса TBaseArray мало относятся к методу find.


Насчет перегрузки функций, я думаю что так и буду делать. Тогда еще такой маленький вопрос. А можна ли перегружать свойства?


M
Alexeis
Модератор: используйте подсветку кода.


Это сообщение отредактировал(а) Alexeis - 7.6.2008, 11:09
PM MAIL   Вверх
Beltar
Дата 7.6.2008, 08:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Код

TIntArray=class(TBaseArray)
  private
    function cmp(a,b:pointer):integer;override;

    function ConstToPointer(AValue:variant):pointer;override;

    function GetItem(i:integer):variant;override;
    procedure SetItem(i:integer;const Value:variant);override;


А зачем тогда ООП, если все подряд в наследнике переписывать?? В protected надо было объявить.

И что метод Find ищет-таки? Перебирает указатели, считая, что они определеного типа. Ну допустим у тебя запихан туда Integer, а ты ищешь Double. Внимание вопрос, а кому принадлежат еще 4 байта идущие после целого и что произойдет когда программа попытается их прочитать? Вот что-то мне подсказывает, что так можно и AV схлопотать.

Код

 try
    new(p);
    p^:=AValue;
    result:=p;
  except
    on Exception do begin
      ShowMessage('Несуміні типи');
    end;
  end;


Зачем использовать on, Если ты все равно не проверяешь тип исключения?


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. smile(с) я, хотя может и нет
Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

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

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

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

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


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

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


 




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


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

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