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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как избавиться от вариантов в полиморфизме? 
V
    Опции темы
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   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

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

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

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

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


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

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


 




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


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

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