Подтвердить что ты не робот

Когда класс реализует интерфейс потомка, почему он автоматически не учитывает реализацию базового интерфейса?

Какая причина этого не будет компилироваться?

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 и быть совместимым с типом?

4b9b3361

Ответ 1

Это так, потому что ранний 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.

Ответ 2

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

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

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