powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Наследование Интерфейсов. Зачем перечислять про-родителей?
18 сообщений из 18, страница 1 из 1
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006798
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С классами все понятно: Класс-наследник должен указать лишь класс-родителя, а цепочку про-родителей перечислять не нужно.
Но, почему при объявлении интерфейсного класса нужно указать и сам интерфейс и его про-родителей?

Выглядит, как “лишняя” работа. Но, м.б. есть какая-то польза или объяснение ?
См. ниже пример
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
type
   IIntrf_Parent = interface(IInterface)
   end;

   IIntrf_Child  = interface(IIntrf_Parent)
   end;

   TClass_Child  = class(TInterfacedObject, IIntrf_Child)
   end;

var
  l_Itf: IIntrf_Parent;
  l_Obj: TClass_Child;
begin

  l_Itf := l_Obj;  // ОШИБКА компиляции: Несовместимые Типы! 

  // Оказывается, родительский интерфейс IIntrf_Parent тоже нужно добавить в описание класса TClass_Child

end;
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006830
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А где IID? Без этого точно работать не будет!
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006837
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st,
Или добавь к классу описание IIntrf_Parent.

Код: pascal
1.
2.
3.
 
TClass_Child  = class(TInterfacedObject, IIntrf_Child, IIntrf_Parent)
end;
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006847
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st,

то, что вы написали, во-первых, про это прямо в документации написано:
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Interface_References_(Delphi)
Да, так спроектировано. В Java и C# если объект реализует методы какого-то интерфейса, он обязан реализовать методы и всех интерфейсов, от которого тот произошел. В Delphi такого требования нет. Соответственно, нет и поддержки интерфейсов-предков.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006865
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62
В Delphi такого требования нет
Чушь. Методы все равно нужно реализовать все
Artem.1st
Выглядит, как “лишняя” работа. Но, м.б. есть какая-то польза или объяснение ?
Так сделано. Класс должен знать какие интерфейсы он реализует

Вот так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
var
  l_Parent: IIntrf_Parent;
  l_Child: IIntrf_Child;
  l_Obj: TClass_Child;
begin

  l_Child := l_Obj;
  l_Parent := l_Child; 
end;

будет работать.

Я так понимаю, что ноги растут в возможности переопределить реализацию метода интерфейса в наследнике.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
type
  IParent = interface
    ['{........}']
    procedure Proc;
  end;

  IChild = interface(IParent)
    ['{........}']
  end;

  TParentImpl = class(TInterfacedObject, IParent)
    procedure Proc;
  end;

  TChild1Impl = class(TParentImpl, IChild)
    procedure Proc;
  end;

  TChild2Impl = class(TParentImpl, IParent, IChild)
    procedure Proc;
  end;

procedure TParentImpl.Proc;
begin
  ShowMessage('Parent');
end;

procedure TChild1Impl.Proc;
begin
  ShowMessage('Child1');
end;

procedure TChild2Impl.Proc;
begin
  ShowMessage('Child2');
end;

var
  LParent: IParent;
  LChild: IChild;
begin
  LChild := TChild1Impl.Create;
  LChild.Proc;  // Child1
  LParent := LChild;
  LParent.Proc;  // Child1
  LChild.QueryInterface(IParent, LParent);
  LParent.Proc;  // Parent

  LChild := TChild2Impl.Create;
  LChild.Proc;  // Child2
  LParent := LChild;
  LParent.Proc;  // Child2
  LChild.QueryInterface(IParent, LParent);
  LParent.Proc;  // Child2

  LParent := TChild1Impl.Create;
  LParent.Proc;  // Parent

  LParent := TChild2Impl.Create;
  LParent.Proc;  // Child2
end;

...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006883
Соколинский Борис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st
Но, м.б. есть какая-то польза или объяснение ?
Объяснение в том, что у интерфейсов нет инкапсуляции. Соответственно, наследник интерфейса - это просто декларация дополнительных методов, а не совместимость функционала.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006947
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Класс должен знать какие интерфейсы он реализует

Хочется найти какую-то полезную логику: Зачем, указывая интерфейс-наследник, нужно еще перечислять цепочку его родителей?
Наверное, есть какая-то польза?
Спасибо за ответы.

s62
Artem.1st,
то, что вы написали, во-первых, про это прямо в документации написано:
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Interface_References_(Delphi)

Спасибо за ссылку, но пример от Embarcadero какой-то странный, см. я скопировал и дописал комментарий в последней строке.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
 type
   IAncestor = interface
   end;
   IDescendant = interface(IAncestor)
     procedure P1;
   end;
   TSomething = class(TInterfacedObject, IDescendant)
     procedure P1;
     procedure P2;
   end;
      // ...
 var
   D: IDescendant;
   A: IAncestor;
 begin
   D := TSomething.Create;  // works!
   A := TSomething.Create;  // error
   D.P1;  // works!
   D.P2;  // error    ...........  так написано на сайте Embarcadero! Но, неужели здесь "error" ?
 end;
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006957
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Соколинский Борис
наследник интерфейса - это просто декларация дополнительных методов, а не совместимость функционала.

Но, ведь в Run-time есть совместимость между интерфейсами (Родитель < Наследник)
А в Compile-Time, оказывается, недостаточно указать Наследника, еще через запятую нужно указать его Родителя(й).
Здесь ищется какая-то польза .
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006960
Соколинский Борис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st
Но, ведь в Run-time есть совместимость между интерфейсами(Родитель < Наследник)
Это совместимость на уровне деклараций, а не функционала.
Коль скоро нет инкапсуляции, нет и гарантии что наследник будет оперировать теми же данными, что родитель.
Например, в случае делегирования.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006985
s62
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st,
автор так написано на сайте Embarcadero! Но, неужели здесь "error" ?Да, error.
An interface-type expression gives you access only to methods and properties declared in the interface, not to other members of the implementing class.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40006994
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
s62
Да, error.
An interface-type expression gives you access only to methods and properties declared in the interface, not to other members of the implementing class.

Да, Вы правы, там все верно.
Я повелся, что “пример из документации похож на мой” 22211314 поэтому невнимательно его смотрел. Спасибо, за уточнение.
Т.е. мой пример совсем на другую тему(наследование интерфейсов 22211195 ), поэтому вопрос все еще актуален ...
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007112
ma1tus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem.1st
Здесь ищется какая-то польза .

см.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007138
zedxxx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Artem.1st ,

Код: pascal
1.
2.
3.
4.
5.
6.
var
  l_Itf: IIntrf_Parent;
  l_Obj: TClass_Child;
begin

  l_Itf := l_Obj;  // ОШИБКА компиляции: Несовместимые Типы! 



А не надо смешивать объекты и интерфейсы. Напишите вот так, и всё будет работать (только интерфейсам, естественно, GUID-ы надо добавить, как писали выше):

Код: pascal
1.
l_Itf := TClass_Child.Create as IIntrf_Parent;



Соответственно, и здесь тоже самое:
Код: pascal
1.
2.
3.
4.
5.
6.
var
   D: IDescendant;
   A: IAncestor;
 begin
   D := TSomething.Create;  // works!
   A := TSomething.Create as IAncestor;  // works too!
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007157
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zedxxx,

Не будет эта хрень работать.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007159
zedxxx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Kazantsev Alexey, Что значит "не будет", если оно работает? Запусти компилятор, убедись.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007161
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
zedxxx,

Компилируется <> работает.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007164
zedxxx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Упс, точно. Но выход есть:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
type
  IIntrf_Parent = interface(IInterface)
    ['{C946FF0A-D897-43FB-A5C6-F5B870B9B3A3}']
    procedure P1;
  end;

  IIntrf_Child  = interface(IIntrf_Parent)
    ['{2E0D5362-38F8-4787-93B3-F44CB26FC015}']
    procedure P2;
  end;

  TClass_Parent = class(TInterfacedObject, IIntrf_Parent)
  private
    procedure P1;
  end;

   TClass_Child  = class(TClass_Parent, IIntrf_Child)
   private
     procedure P2;
   end;

procedure TClass_Parent.P1;
begin
  Writeln('P1');
end;

procedure TClass_Child.P2;
begin
  Writeln('P2');
end;

procedure Test;
var
  VParent: IIntrf_Parent;
  VChild: IIntrf_Child;
begin
  VParent := TClass_Child.Create;
  VParent.P1;

  VChild := TClass_Child.Create;
  VChild.P1;
  VChild.P2;
end;



А вот объяснение, почему не работает наследование интерфейса https://stackoverflow.com/a/4380371/6219657

авторIf an implementing class does not declare that it supports an inherited interface, then the class will not be assignment compatible with variables of the inherited interface. The code sample you posted should work fine (using the IChild interface), but if you try to assign from an instance of TMyClass to a variable of IParent, then you'll run into trouble.

The reason is because COM and ActiveX allow an implementation to implement a descendent interface (your IChild) but deny the ancestor of that interface (IParent). Since Delphi interfaces are intended to be COM compatible, that's where this goofy artifact comes from.
...
Рейтинг: 0 / 0
Наследование Интерфейсов. Зачем перечислять про-родителей?
    #40007277
Artem.1st
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ma1tus
Artem.1st
Здесь ищется какая-то польза .

см.

Спасибо.
Это полезный блог, в соседней статье я нашел ответ на вопрос темы.
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Наследование Интерфейсов. Зачем перечислять про-родителей?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]