Когда класс реализует интерфейс-потомок, почему он не считается автоматически реализующим базовый интерфейс? - PullRequest
18 голосов
/ 12 декабря 2011

Почему это не скомпилируется?

type
  IInterfaceA = interface ['{44F93616-0161-4912-9D63-3E8AA140CA0D}']
    procedure DoA;
  end;

  IInterfaceB = interface(IInterfaceA) ['{80CB6D35-E12F-462A-AAA9-E7C0F6FE0982}']
    procedure DoB;
  end;

  TImplementsAB = class(TSingletonImplementation, IInterfaceB)
    procedure DoA;
    procedure DoB;
  end;

var
  ImplementsAB: TImplementsAB;
  InterfaceA: IInterfaceA;
  InterfaceB: IInterfaceB;
begin
  ImplementsAB := TImplementsAB.Create;
  InterfaceA := ImplementsAB; >> incompatible types
  ...
end

Напротив, вот как я это делаю:

InterfaceA := ImplementsAB as InterfaceB;

или

InterfaceA := InterfaceB;

Я имею в виду, если IInterfaceB наследует от IInterfaceA, а TImplementsAB реализует IInterfaceB, было бы не логично также реализовать IInterfaceA и быть совместимым с типом?

Ответы [ 2 ]

28 голосов
/ 12 декабря 2011

Это так, потому что в раннем OLE / COM была ошибка, и Borland решил быть совместимым с ней.Это упоминается в этой статье: Новая функция языка Delphi: множественное наследование для интерфейсов в Delphi для .NET .Решение состоит в том, чтобы перечислить все интерфейсы предков явно в классе, как писал Микаэль.

Некоторые цитаты из связанной статьи:

Проблема была в самом COM.Чтобы загрузить модуль, COM должен загрузить DLL, GetProcAddress в известную точку входа, которая должна была быть экспортирована из DLL, вызвать функцию DLL для получения интерфейса IUnknown, а затем QueryInterface для IClassFactory.Проблема заключалась в том, что когда Microsoft добавила поддержку IClassFactory2, они добавили QueryInterface для IClassFactory2 после существующего кода, который запрашивал IClassFactory.IClassFactory2 будет запрашиваться только в случае сбоя запроса для IClassFactory.

Таким образом, COM никогда не будет запрашивать IClassFactory2 на любом COM-сервере, который реализует как IClassFactory2, так и IClassFactory.

Эта ошибка существовала в COM в течение длительного времени.время.Microsoft заявила, что не может исправить загрузчик COM с пакетом обновления ОС, потому что и Word, и Excel (в то время) полагались на ошибочное поведение.Независимо от того, исправлено ли это в последних выпусках COM или нет, Borland должен предоставить какой-то способ сохранить это поведение в Win32 Delphi на обозримое будущее.Внезапное добавление всех предков в реализующий класс, которого раньше не было, может привести к поломке существующего кода, который непреднамеренно попадает в тот же шаблон, что и COM-загрузчик.

6 голосов
/ 12 декабря 2011

Еще один способ заставить его работать - включить оба интерфейса в объявление класса.

TImplementsAB = class(TSingletonImplementation, IInterfaceA, IInterfaceB)
  procedure DoA;
  procedure DoB;
end;

Полагаю, это то, что требуется компилятору, чтобы понять, что TImplementsAB реализует как IInterfaceA, так иIInterfaceB.

...