Кроме того, в .NET обязательно в конструкторе потомка первым оператором должен быть вызван конструктор предка; в Object Pascal это необязательно. Если в PascalABC.NETконструктор предка вызывается из конструктора потомка, то этот вызов должен быть первым оператором. Если конструктор предка явно не вызывается из конструктора потомка, то неявно первым оператором в конструкторе потомка вызывается конструктор предка по умолчанию (т.е. без параметров). Если такого конструктора у предка нет (это может быть класс, откомпилированный другим .NET-компилятором или входящий в стандартную библиотеку классов - все классы, откомпилированные PascalABC.NET, имеют конструктор по умолчанию), то возникает ошибка компиляции.
Например:
type
A = class
i: integer;
// конструктор по умолчанию не определен явно, поэтому генерируется автоматически
constructorCreate(i: integer);
begin
Self.i := i;
end;
end;
B = class(A)
j: integer;
constructorCreate;
begin
// конструктор по умолчанию базового класса вызывается автоматически
// конструктор по умолчанию определен явно, поэтому не генерируется автоматически
j := 1;
end;
constructorCreate(i,j: integer);
begin
inherite dCreate(i);
Self.j := j;
end;
end;
C = class(B)
// класс не определяет конструкторов, поэтому
// конструктор по умолчанию и constructorCreate(i,j: integer)
// генерируются автоматически, вызывая в своем теле соответствующие конструкторы предка
end;
Виртуальные методы и полиморфизм
Полиморфизм (от греч . много форм) - это свойство классов, связанных наследованием, иметь различную реализацию входящих в них методов, и способность переменной базового класса вызывать методы того класса, объект которого содержится в этой переменной в момент вызова метода.
Полиморфизм используется в ситуации, когда для группы взаимосвязанных объектов требуется выполнить единое действие, но каждый из этих объектов должен выполнить указанное действие по-своему (т.е. у действия возникает много форм). Для этого определяется базовый для всех объектов класс с виртуальными методами, предусмотренными для меняющегося поведения, после чего эти методы переопределяется в потомках.
Для пояснения рассмотрим переопределение метода в подклассе:
type
Base = class
public
procedurePrint;
begin
writeln('Base');
end;
end;
Derived = class(Base)
public
procedurePrint;
begin
writeln('Derived');
end;
end;
Присвоим переменной базового класса Base объект производного класса Derived и вызовем метод Print.
varb: Base := new Derived;
b.Print;
Какая версия метода Print вызывается - класса Base или класса Derived? В данном случае решение будет принято еще на этапе компиляции: вызовется метод Print класса Base, заявленного при описании переменной b. Говорят, что имеет место раннее связывание имени метода с его телом. Если же решение о том, какой метод вызывать, принимается на этапе выполнения программы в зависимости от реального типа объекта, на который ссылается переменная b, то в данном случае вызывается метод Derived.Print (говорят также, что имеет место позднее связывание ). Методы, для которых реализуется позднее связывание, называются виртуальными , а переменная базового класса, через которую осуществляется вызов виртуального метода, - полиморфной переменной . Таким образом, полиморфизм реализуется вызовом виртуальных функций через переменную базового класса. Тип класса, который хранится в данной переменной на этапе выполнения, называется динамическим типом этой переменной.
Для того чтобы сделать метод виртуальным, следует в объявлении этого метода после заголовка указать ключевое слово virtualс последующей ;. Для переопределения виртуального метода следует использовать ключевое слово override:
type
Base = class
public
procedurePrint; virtual;
begin
writeln('Base');
end;
end;
Derived = class(Base)
public
procedurePrint; override;
begin
writeln('Derived');
end;
end;
Теперь в аналогичном участке кода.
varb: Base := new Derived;
b.Print;
вызывается метод Print класса Derived за счет того что решение о вызове метода откладывается на этап выполнения программы.
Читать дальше