Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Полиморфный (или абстрактный) стек


Автор: saneea 21.4.2008, 23:32
Пишу курсовой, и будет у меня там много стеков работающих с разными типами. Можно конечно каждый отдельно описать, но за такое "по головке никто не погладит". Вот я и думаю, как это грамотно организовать. Помогите пожалста с примерчиком и проясните как это называеться: полиморфизм или абстракция?

Автор: saneea 21.4.2008, 23:54
У меня вот есть одна догадка:

Код

TStack=class
tab: array [1..10] of variant;
up: integer;
procedure push(x: variant);
function pop: variant;
constructor Create;
end;

procedure TStack.push(x: variant);
begin
inc(up);
tab[up]:=x;
end;

function TStack.pop: variant;
begin
pop:=tab[up];
dec(up);
end;

constructor TStack.Create;
begin
up:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
st:=TStack.Create;
end;


Но мне кажеться что это не совсем грамотно... хочу полиморфизм...  smile 

Автор: MaXL 22.4.2008, 09:18
saneea, а почему это не является грамотным то ?=) Вроде бы всё нормально, и не прийдётся ни классы описывать, ни методы, и при этом для разных типов разные.

Автор: volvo877 22.4.2008, 11:29
Цитата(MaXL @  22.4.2008,  08:18 Найти цитируемый пост)
а почему это не является грамотным то ?=)
Хотя бы потому, что
Код

var stack: TStack
...
  stack.push(10);
  stack.push('20');
...
будет пропущено, а грамотная реализация стека должна работать только с однотипными данными...

Автор: MaXL 22.4.2008, 13:37
Цитата
у меня там много стеков работающих с разными типами


volvo877, мне почему то кажется, что в этом предложении именно говориться, что будет несколько стэков, которые и будут хранить разные типы данных, т.е. один для строк, другой для чисел, третий ещё для чего-нибудь там. А в вашем примере о том, что либо стэк, либо о том, что кривой код, либо о том, что стэк должен сам из '10' преобразовать в 10.
Т.е. мы ведь знаем, какой стэк используем(т.е. для каких данных он создан), таким и пользуемся:
Код

var stack: TStack
...
  stack.push(10);
  stack.push(StrToInt('20')); //до кучи просто ;-)
...

Автор: volvo877 22.4.2008, 14:25
А если ты соизволишь прочитать внимательно, то увидишь, что я имел в виду: грамотно построенный стек должен выдать ошибку на том примере, который я привел, а не выполнять его, поскольку стек должен хранить ИЛИ строки, ИЛИ целые, но никак не одно и другое вместе! 

Автор: saneea 22.4.2008, 15:36
Цитата(volvo877 @ 22.4.2008,  14:25)
А если ты соизволишь прочитать внимательно, то увидишь, что я имел в виду: грамотно построенный стек должен выдать ошибку на том примере, который я привел, а не выполнять его, поскольку стек должен хранить ИЛИ строки, ИЛИ целые, но никак не одно и другое вместе!

Да, именно так. Хочу сделать один базовый класс для всех типов данных, а от него родить ещё к примеру один класс для целых, а другой для строк. Просто очень хочеться это сделать грамотно...

Помогите пожааалста...

Автор: Rennigth 22.4.2008, 15:55
saneea, тогда в базовом классе стека храни указатели на данные, а в наследниках только приводи к нужному тебе типу. 

Автор: MaXL 22.4.2008, 16:14
volvo877, ну так я и говорю, что если создать стэк, в котором будут только числа к примеру, и если мы попытаемся туда запихать строку, то это просто кривой код будет...
Код

var 
  intStack: TStack;
  //...
  stack.push('12');
  //...

Автор: volvo877 22.4.2008, 16:30
Это возможности простого стека, а не ГРАМОТНОГО, пойми ты это!!! Вообще-то Стек должен в Compile-Time предотвращать попытки занесения "чужого" типа. Почему ты не описываешь всегда у процедур/функций, которыми пользуешься, бестиповые параметры? Ты ж и так знаешь, что передавать, а? И не ошибаешься никогда, верно? Так передавай в бестиповый, а внутри уже приводи к тому типу, что тебе нужен. Ан нет, тебе, как видно,  удобнее, чтобы происходила доп. проверка на совместимость типа, что ж ты тут-то советуешь неизвестно что?

Автор: saneea 22.4.2008, 16:31
Цитата(Rennigth @ 22.4.2008,  15:55)
saneea, тогда в базовом классе стека храни указатели на данные, а в наследниках только приводи к нужному тебе типу.

А можно пример? А то я не совсем понимаю как привести к нужному типу...

Автор: volvo877 22.4.2008, 16:32
saneea, ты PM читал?

Автор: saneea 22.4.2008, 19:30
Цитата(volvo877 @ 22.4.2008,  16:32)
saneea, ты PM читал?

Что такое РМ?

Автор: volvo877 22.4.2008, 20:36
Личное сообщение, у тебя есть ссылка вверху страницы "... новых писем"

Автор: MaXL 23.4.2008, 05:34
volvo877, я просто говорю, что в данном случае проще пользоваться именно такой структурой.
saneea, выложишь потом код, с реализацией всех этих стэков и мы сравним.

Автор: Felan 23.4.2008, 08:15
Цитата(saneea @  22.4.2008,  17:36 Найти цитируемый пост)
Да, именно так. Хочу сделать один базовый класс для всех типов данных, а от него родить ещё к примеру один класс для целых, а другой для строк. Просто очень хочеться это сделать грамотно...

Я, в принципе соглашусь с volvo877, незачем в стек пихать все подрят. Но раз тебе именно этого хочется, то грамотно будет сделать интерфейс, который должен будет реализовывать каждый элемент, который может быть добавлен в стек, а стек уже должен работать с каждым элементом через этот интерфейс. В этом случае для простых типов придется делать обертки (классы).
Но это позволит тебе избежать сложного дерева наследования, если вдруг у тебя действительно с сильно разными элементами надо работать.

Автор: saneea 23.4.2008, 19:18
Ого... Чесно говоря я думал всё это по проще... Есть ещё одна идея, но для этого мне нужно знать, можно ли объявить тип, который будет виден только в этом классе. Тогда можно будет создать класс, в котором объявить тип TType=variant (к примеру), сделать все операции с этим относительно этого типа(относительно TType), а в классах предках просто переопределять этот тип (к примеру TType=integer или TType=string). Можно определить тип в классе?

Автор: MaXL 24.4.2008, 07:04
saneea, ну вроде бы как можно, скорее всего так:
Код

TStack = class
    type
      TType = Variant;
    private
      Stack: array[0..MAX_STACK] of TType;
      StackPos: integer;
    public
      procedure Push(Value: TType);
      function Pop: TType;
  end;

Автор: Felan 24.4.2008, 09:17
А обратно из Variant ты как будешь переводить? Как ты определишь в рантайме, какой именно у тебя тип на самом деле?

Цитата(saneea @  23.4.2008,  21:18 Найти цитируемый пост)
Ого... Чесно говоря я думал всё это по проще...

Так ты проще хотел или грамотно? smile

Цитата(saneea @  23.4.2008,  21:18 Найти цитируемый пост)
сделать все операции с этим относительно этого типа(относительно TType), а в классах предках просто переопределять этот тип (к примеру TType=integer или TType=string)

Относительно типа не получится. Отностиельно базового класса или интерфеса - можно. В предках ничего переопределить нельзя, можно только в потомках переопределить что-то.

Автор: saneea 24.4.2008, 12:41
Цитата

А обратно из Variant ты как будешь переводить? Как ты определишь в рантайме, какой именно у тебя тип на самом деле?


Да, я об этом уже подумал...

Цитата

Так ты проще хотел или грамотно? smile 

Я хотел и то и другое smile

Я помню мы ещё на первом курсе проходили C++, и было там такая вещь как шаблоны. Только это кажется далеко не полиморфизм.

Автор: Esperito 24.4.2008, 16:35
Можно сделать стек, содержащий Variant'ы, при создании конструктору передавать желаемый тип (например vtInteger), а потом запрещать процедуре Push принимать любой другой тип Variant'а.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)