Для потомков при использовании их "на месте" прародителей любого уровня имеется два основных варианта совместимости типов (по вызовам и по присваиваниям) между:
1. экземплярами объектов,
2. указателями на экземпляры объектов,
3. формальными и фактическими параметрами.
Потомки могут использоваться вместо прародителей (но не наоборот!) по следующей причине: используемый тип должен для совместимости полностью "заполнять" поля типа, вместо которого он подставляется.
Например:
aDot:=aCircle;
aDot:=aArc;
{aCircle:=aDot - так нельзя!}
При этом в наш объект, которому присваивается значение, копируются только те поля данных, которые имеются в Dot, а остальные оказываются ненужными и игнорируются. Если бы мы попытались сделать присваивания в обратную сторону (aCircle:=aDot или aArc:=aDot), часть полей результата не смогла бы заполниться. Поэтому присваивания типа "потомок:=прародитель" недопустимы. Стоит отметить, что описанные выше разрешенные присваивания объектов как таковых в последующих версиях PASCAL невозможны, и работа с объектами идет только через указатели (смотри далее раздел про Delphi).
Для указателей присваивание pDot:=pCircle допустимо, а pCircle:=pDot недопустимо, т.е. указателю на прародителя можно присвоить указатель на потомка, но не наоборот. Это правило логически вытекает из описанного выше правила совместимости для объектов. Оно сохранено в Delphi, хотя его основа — правило присваивания объектов — в Delphi ликвидировано. Поэтому изучение объектной модели Turbo Pascal полезно для правильного понимания объектной модели Delphi.
В TurboPascal имеется предопределенный тип Pointer, совместимый по присваиванию для всех типов указателей, то есть переменной типа Pointer можно присвоить указатель любого типа. Но при дальнейшем ее использовании следить за работой с указателями на тип должен сам программист. Обратное присваивание (указателю на объект указателя типа Pointer) возможно только с помощью явного указания приведения типов.
Особенностью рассмотренных правил совместимости является то, что при работе с указателями на полиморфные объекты (т.е. при наличии в объектах виртуальных методов) бывает заранее неизвестно, какой тип вызовется. Вызов:
pDot^.Show
может показать и точку, и круг, и дугу (и даже еще неизвестного нам потомка) в зависимости от того, указатель на какую фигуру был присвоен указателю pDot. Это может зависеть от различных условий. Например, от решения пользователя в программе. В приводимом ниже примере указателю типа tpDot намеренно дано название не pDot, а pFigure, чтобы подчеркнуть, что он может указывать на произвольную фигуру — потомок tDot:
var FigKey:Char;
pFigure:tpDot;
begin
...
outTextXY('Choose type of a figure:0-dot,1-circle,2-arc',0,10);
readln(FigKey);
case FigKey of
'0':pFigure:=pDot;
'1':pFigure:=pCircle;
'2':pFigure:=pArc;
end;
...
pFigure^.Show; {не забыть, что до этого экземпляр должен был быть
инициализирован конструктором!}
...
end;
Выбор конкретного виртуального метода для объекта pFigure^ происходит во время выполнения программы.