Интерфейсной переменной можно присвоить значение объектной переменной при условии, что объект (точнее его класс) реализует упомянутый интерфейс:
var Intf: ITextReader; // интерфейсная переменная Obj: TTextReader; // объектная переменная begin ... Intf := Obj; // В переменную Intf копируется //ссылка на объект Obj ... end; |
Такая совместимость сохраняется в производных классах. Если класс реализует некоторый интерфейс, то и все его производные классы совместимы с этим интерфейсом (см. рисунок 6.3):
type TTextReader = class(TInterfacedObject, ITextReader) ... end; TDelimitedReader = class(TTextReader) ... end; var Intf: ITextReader; // интерфейсная переменная Obj: TDelimitedReader; // объектная переменная begin ... Intf := Obj; ... end; |

Рисунок 6.3.
Классы TTextReader, TDelimitedReader и TFixedReader совместимы
с интерфейсом ITextReader
Однако, если класс реализует производный интерфейс, то это совсем не означает, что он совместим с базовым интерфейсом (см. рисунок 6.4):
type ITextReader = interface(IInterface) ... end; IExtendedTextReader = interface(ITextReader) ... end; TExtendedTextReader = class(TInterfacedObject, IExtendedTextReader) ... end; var Obj: TExtendedTextReader; Intf: ITextReader; begin ... Intf := Obj; // Ошибка! Класс TExtendedTextReader // не реализует // интерфейс IExtendedTextReader. ... end; |

Рисунок 6.4.
Класс TExtendedTextReader совместим лишь с интерфейсом
IExtendedTextReader
Для совместимости с базовым интерфейсом нужно реализовать этот интерфейс явно:
type TExtendedTextReader = class(TInterfacedObject, ITextReader, IExtendedTextReader) ... end; |
Теперь класс TExtendedTextReader совместим и с интерфейсом ITextReader, поэтому следующее присваивание корректно:
Intf := Obj; |
Исключением из только что описанного правила является совместимость всех снабженных интерфейсами объектов с интерфейсом IInterface:
var Obj: TExtendedTextReader; Intf: IInterface; begin ... Intf := Obj; // Правильно, IInterface - //особый интерфейс. ... end; |