Помощь - Поиск - Пользователи - Календарь
Полная версия: ООП
Форум «Всё о Паскале» > Pascal, Object Pascal > Теоретические вопросы
Client
Всем привет!
Начал изучать ООП и появились вопросы. Вроде с наследованием и инкапсуляцией понятно, а вот с полиморфизмом не понятно. Можете объяснить для чего он нужен и что такое виртуальные методы?
volvo
Ну, ты же здесь был: ООП. Объектно-ориентированное программирование ? Там написано ,что такое полиморфизм, и как он реализуется... Что-то непонятно?
Client
Цитата
Полиморфизм.
Возможность определения единого по имени действия (процедуры или функции), применимого одновременно ко всем объектам иерархии наследования, причем каждый объект может "заказывать" особенность реализации этого действия над "самим собой".
В наследовании есть родитель и потомок, где потомок сохраняет поля и методы родителя. А в полиморфизме наоборот?
Цитата
причем каждый объект может "заказывать" особенность реализации этого действия над "самим собой".
Это совсем не понятно(
volvo
Не путай теплое с мягким... Наследование - это необходимое условие полиморфизма, нельзя сделать полиморфность без наследования. Смотри:
type
ta = object
constructor init;
procedure print; virtual;
end;

constructor ta.init;
begin end;
procedure ta.print;
begin writeln('TA object') end;

procedure proc(var obj: ta);
begin
obj.print;
end;

type
tb = object(ta)
constructor init;
procedure print; virtual;
end;

constructor tb.init;
begin inherited init; end;
procedure tb.print;
begin writeln('TB object') end;

var
A: ta;
B: tb;
begin
a.init; proc(a);
b.init; proc(b);
end.
Чувствуешь? Proc принимает объект типа TA или его потомка (неважно, насколько далекого, может "сын", а может и "внук", "правнук" и т.д.), и вызывает метод нужного типа. То есть, для того, чтобы напечатать значение любого потомка достаточно "заказать" в определенном классе нужную тебе функциональность. Я "заказал" реализацию TB.print, что заказал, то и получил... Только наследованием (без виртуализации) этого добиться нельзя. Если в вышеприведенном примере не будет виртуальных методов, то процедура не будет полиморфной, она для любого переданного объекта будет вызывать метод TA.print...
Client
Цитата
Наследование - это необходимое условие полиморфизма, нельзя сделать полиморфность без наследования.
O_o незнал.
procedure proc(var obj: ta);
begin
obj.print;
end;
Понял, для каждого потомка будет свой метод smile.gif
constructor tb.init;
begin inherited init; end;

А что это такое inherited?
proc(b);
это тоже самое что и
b.print
Спасибо за помощь!
volvo
Цитата
А что это такое inherited?
Это вызов метода из непосредственного родителя... Можно, конечно, сделать так:
constructor tb.init;
begin ta.init; end;
, но подумай, что получится, если между TA и TB будет внесен еще один наследник. Было:
type
ta = object
end;
tb = object(ta)
end;
, стало:
type
ta = object
end;
ta2 = object(ta)
end;
tb = object(ta2)
end;
, тогда прямое указание ta.init придется поменять на ta2.init, если же использовался inherited - ничего менять не надо будет...

P.S.
Да, proc(b) и b.print будут выполнять одно и то же действие, если больше ты ничего не менял в программе.
Client
uses crt;
type
ta = object
constructor init;
procedure print; virtual;
end;

constructor ta.init;
begin end;
procedure ta.print;
begin writeln('TA object') end;

procedure proc(var obj: ta);
begin
obj.print;
end;

type
ta2 = object(ta)
constructor init;
procedure print; virtual;
end;

constructor ta2.init;
begin end;
procedure ta2.print;
begin writeln('TA2 object') end;


type
tb = object(ta2)
constructor init;
procedure print; virtual;
end;

constructor tb.init;
begin {inherited init;} end;
procedure tb.print;
begin writeln('TB object') end;

var
A: ta;
B: tb;
c:ta2;
begin
clrscr;
a.init; proc(a);
b.init; proc(b);
c.init; proc©;
readkey
end.
Цитата
но подумай, что получится, если между TA и TB будет внесен еще один наследник
Добавил наследника, закоментировал
inherited init;
все равно работает О_о
если я правильно понял про наследника


Добавлено через 4 мин.
Упс... Там же по идеи должны присваиваться какие-то значения полям, но их нету. Если были бы, то не прокатило, да?
volvo
Цитата
все равно работает О_о
Да, работает... Только некорректно это. При инициализации потомка надо сначала инициализировать предка. Ты этого не делаешь. Хочешь, набросаю пример программы, при котором БЕЗ вызова всей цепочки Init-ов получишь аварийный вылет? smile.gif
Client
Цитата
При инициализации потомка надо сначала инициализировать предка. Ты этого не делаешь
Инициализация?? т.е. присваивание полям значений или создание объекта?
Цитата
Хочешь, набросаю пример программы, при котором БЕЗ вызова всей цепочки Init-ов получишь аварийный вылет?
yes2.gif
volvo
Цитата
Инициализация?? т.е. присваивание полям значений или создание объекта?
И то и другое... Вот, например, при инициализации базового типа выделяется память под строку, а все остальные - передают в этот базовый тип результат своей инициализации: Нажмите для просмотра прикрепленного файла

Где-нибудь цепочка Init-ов прервется - будет разыменование нулевого указателя, ошибка... Я надеюсь, понятно, что в конструкторе TA2, например, если какое-то дополнительное условие не выполняется, я могу поменять строку с 'no error' на любую другую? И в конструкторе TB тоже. И даже в TA...
Client
УРЯЯЯЯ!!! я понял) тут мы просто используем метод предка, т.е. если у предка 100 полей, а у потомка 2 доп. поля то можно вызвать метод предка по обработке полей и добавить действия над другими двумя полями)
Цитата
получишь аварийный вылет?
Что-то его нету blum.gif
Цитата
И то и другое...
В данном случае же есть экземпляр объекта, т.е. тут инициализация объекта это просто присваивание значений элементам?
volvo
Цитата
тут мы просто используем метод предка, т.е. если у предка 100 полей, а у потомка 2 доп. поля то можно вызвать метод предка по обработке полей и добавить действия над другими двумя полями)
Если ты про конструктор - то я тебе еще больше скажу: методы потомка ДОЛЖНЫ вызывать методы предка для инициализации/присвоения его (предка) полей, потому что никто не сможет инициализировать поле лучше, чем объект, в котором это поле добавляется.

Цитата
Что-то его нету
Чего нет? Вылета? Это не проблема ООП, это проблема Турбо-Паскаля... Любой нормальный компилятор при попытке разыменовать нулевой указатель вылетит с 216-ой ошибкой... Турбо-Паскаль же ошибку замалчивает (спрашивается, ЗАЧЕМ? Программа-то не работает правильнее от того, что не происходит вылет), но при этом печатает тебе на экране откровенный бред.
Client
Вроде понял) Спасибо за ответы!
fedyafed
Листинг программы от Дата 15.02.2009 17:01 содержит виртуальные методы. Как нужно настроить Borland Pascal 7.0 , чтобы он с ними корректно работал?
volvo
Никак не нужно настраивать, он по умолчанию прекрасно работает с виртуальностью. Если нет - меняй компилятор, у тебя кривая сборка.
Гость
А overload и override компилятор не понимает(. Это уже к Delphi?
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.