Сложный полиморфизм. Конструкторы
Существуют три случая, в которых определение типа обьекта на этапе компиляции программы невозможно, и, следовательно, невозможно правильное подключение переопределенного метода. Рассмотрим один из таких случаев.
Пример. Разработать классы для реализации обьекта Комната П, который должен отвечать на запрос о площади пола, выводя результат сразу на экран, и обьекта Трехмерная комната П, который должен отвечать на запрос о площади стен и потолка, также выводя результат на экран.
Класс TRoom2 строим аналогично классу ТRoom, добавив метод выводa результата на экран Print. Класс TVRoomР наследуем от TRoomP, переопределив метод определения площади и метод инициализации полей объекта.
Классы, таким образом, будут описаны следующим образом.
Как правило, в качестве конструктора используют метод инициализации полей, так как его обычно вызывают в начале работы с объектом. При повторном вызове конструктора никаких дополнительных действий не выполняется, метод работает как обычная процедура.
Объявим метод Square виртуальным полиморфным и используя метод Init в качестве конструктора.
Program сase1;
type TRoomP=object
length, width:real; {поля: длина и ширина комнаты)
function Square:real; virtual; {метод определения площади}
procedure Prim; {метод вывода результата на экран}
constructor Init(l,w:real); {конструктор}
end;
Function TRoomP.Square; {тело метода определения плошали}
Begin
Square:=length* width;
End;
Procedure TRoomP.Print; {тело метода вывода результатов}
Begin
WriteLn('Площадь = ', Square:6:2);
{теперь вызов метода происходит через TВM класса }
End;
Constructor TRoomP.Init; {тело конструктора}
Begin
Length:=l;
width:=w;
End;
Type TVRoomP = object(TRoomP)
height:real; {дополнительное поле класса}
function Square:real; virtual; {виртуальный полиморфный метод}
constructor Init(l,w,h:real); {конструктор}
end;
Constructor TVRoomP.Init;
Begin
Inherited Init(l,w); {инициализирует поля базового класса}
height:=h; {инициализируем coбсвeнное поле класса}
End;
Function TVRoomF.Square;
Begin
Square:=inherited Square*height+2*height*(length*width);
End;
Var A:TRoоmP;
B:TVRoomP; {объявляем объекты-переменные}
Begin
A.Init(3.5,5.1); {конструируем объект А}
A.Print; {выведет «Площадь = 17.85»}
B.Init(3.5,5.1,2.7); {конструируем объект В}
В.Рrint; {выведет «Площадь = 94.64» - верно!!!}
End.
Определены три случая, когда использование позднего связывания обязательно:
1) наследуемый метод для объекта производного класса вызывает метод, переопределенный в производном классе - пример такой ситуации рассмотрен выше;
2) объект производного класса через указатель базового класса обращается к методу, переопределенному производным классом;
3) процедура вызывает переопределенный метод для объекта производного класса, переданного в процедуру через параметр-переменную, описанный как объект базового класса (данную ситуацию часто называют «процедурой с полиморфным объектом»).
Примечание. При использовании параметров-значений аргумент-объем копируется. При этом копируется объект типа параметра, т.е. базового. Следовательно, передать в процедуру объект производного класса не удается.
Собственно все три случая сводятся к одному: обращение к полиморфному методу выполняется через указатель базового класса, которому может быть присвоен адрес объекта не только базового, но и производного класса. В теории программирования объект, адресуемый подобным указателем, получил название полиморфного.
Операции присваивания полиморфных объектов. При выполнении операции присваивания для полиморфных объектов следует помнить, что объект, которому присваивается значение, должен быть сконструирован, т.e. для него должен быть вызван конструктор. Если объект сконструирован не был, то операция присваивания выполняется некорректно: поля объекта просто обнуляются, и никаких сообщений об ошибке не выдается. Программа же в этом случае естественно работает не правильно.
Дата добавления: 2015-12-01; просмотров: 1206;