Форум «Всё о Паскале» _ Теоретические вопросы _ ООП
Автор: Client 15.02.2009 20:00
Всем привет! Начал изучать ООП и появились вопросы. Вроде с наследованием и инкапсуляцией понятно, а вот с полиморфизмом не понятно. Можете объяснить для чего он нужен и что такое виртуальные методы?
Автор: volvo 15.02.2009 20:19
Ну, ты же здесь был: http://forum.pascal.net.ru/index.php?showtopic=2085 ? Там написано ,что такое полиморфизм, и как он реализуется... Что-то непонятно?
Автор: Client 15.02.2009 20:27
Цитата
Полиморфизм. Возможность определения единого по имени действия (процедуры или функции), применимого одновременно ко всем объектам иерархии наследования, причем каждый объект может "заказывать" особенность реализации этого действия над "самим собой".
В наследовании есть родитель и потомок, где потомок сохраняет поля и методы родителя. А в полиморфизме наоборот?
Цитата
причем каждый объект может "заказывать" особенность реализации этого действия над "самим собой".
Это совсем не понятно(
Автор: volvo 15.02.2009 21:01
Не путай теплое с мягким... Наследование - это необходимое условие полиморфизма, нельзя сделать полиморфность без наследования. Смотри:
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 15.02.2009 21:16
Цитата
Наследование - это необходимое условие полиморфизма, нельзя сделать полиморфность без наследования.
O_o незнал.
procedure proc(var obj: ta); begin obj.print; end;
Понял, для каждого потомка будет свой метод
constructor tb.init; begin inherited init; end;
А что это такое inherited?
proc(b);
это тоже самое что и
b.print
Спасибо за помощь!
Автор: volvo 15.02.2009 21:37
Цитата
А что это такое 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 15.02.2009 22:34
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;
но подумай, что получится, если между TA и TB будет внесен еще один наследник
Добавил наследника, закоментировал
inherited init;
все равно работает О_о если я правильно понял про наследника
Добавлено через 4 мин. Упс... Там же по идеи должны присваиваться какие-то значения полям, но их нету. Если были бы, то не прокатило, да?
Автор: volvo 15.02.2009 22:40
Цитата
все равно работает О_о
Да, работает... Только некорректно это. При инициализации потомка надо сначала инициализировать предка. Ты этого не делаешь. Хочешь, набросаю пример программы, при котором БЕЗ вызова всей цепочки Init-ов получишь аварийный вылет?
Автор: Client 15.02.2009 22:43
Цитата
При инициализации потомка надо сначала инициализировать предка. Ты этого не делаешь
Инициализация?? т.е. присваивание полям значений или создание объекта?
Цитата
Хочешь, набросаю пример программы, при котором БЕЗ вызова всей цепочки Init-ов получишь аварийный вылет?
Автор: volvo 15.02.2009 23:37
Цитата
Инициализация?? т.е. присваивание полям значений или создание объекта?
И то и другое... Вот, например, при инициализации базового типа выделяется память под строку, а все остальные - передают в этот базовый тип результат своей инициализации: oop_01.pas ( 920 байт )
Кол-во скачиваний: 705
Где-нибудь цепочка Init-ов прервется - будет разыменование нулевого указателя, ошибка... Я надеюсь, понятно, что в конструкторе TA2, например, если какое-то дополнительное условие не выполняется, я могу поменять строку с 'no error' на любую другую? И в конструкторе TB тоже. И даже в TA...
Автор: Client 16.02.2009 20:22
УРЯЯЯЯ!!! я понял) тут мы просто используем метод предка, т.е. если у предка 100 полей, а у потомка 2 доп. поля то можно вызвать метод предка по обработке полей и добавить действия над другими двумя полями)
Цитата
получишь аварийный вылет?
Что-то его нету
Цитата
И то и другое...
В данном случае же есть экземпляр объекта, т.е. тут инициализация объекта это просто присваивание значений элементам?
Автор: volvo 16.02.2009 23:04
Цитата
тут мы просто используем метод предка, т.е. если у предка 100 полей, а у потомка 2 доп. поля то можно вызвать метод предка по обработке полей и добавить действия над другими двумя полями)
Если ты про конструктор - то я тебе еще больше скажу: методы потомка ДОЛЖНЫ вызывать методы предка для инициализации/присвоения его (предка) полей, потому что никто не сможет инициализировать поле лучше, чем объект, в котором это поле добавляется.
Цитата
Что-то его нету
Чего нет? Вылета? Это не проблема ООП, это проблема Турбо-Паскаля... Любой нормальный компилятор при попытке разыменовать нулевой указатель вылетит с 216-ой ошибкой... Турбо-Паскаль же ошибку замалчивает (спрашивается, ЗАЧЕМ? Программа-то не работает правильнее от того, что не происходит вылет), но при этом печатает тебе на экране откровенный бред.
Автор: Client 17.02.2009 0:29
Вроде понял) Спасибо за ответы!
Автор: fedyafed 6.02.2011 14:25
Листинг программы от Дата 15.02.2009 17:01 содержит виртуальные методы. Как нужно настроить Borland Pascal 7.0 , чтобы он с ними корректно работал?
Автор: volvo 6.02.2011 14:49
Никак не нужно настраивать, он по умолчанию прекрасно работает с виртуальностью. Если нет - меняй компилятор, у тебя кривая сборка.
Автор: Гость 6.02.2011 15:23
А overload и override компилятор не понимает(. Это уже к Delphi?