Показать сообщение отдельно
Старый 12.03.2009, 22:52
Stargazer вне форума Посмотреть профиль Отправить личное сообщение для Stargazer Найти все сообщения от Stargazer
  № 44  
Ответить с цитированием
Stargazer

Регистрация: Nov 2008
Сообщений: 528
Цитата:
Сообщение от dimarik Посмотреть сообщение
Термин - это точное определение понятия. Я не понимаю фразы "наследование через интерфейс".

В ООП существует термин "множественное наследование". Но многие языки (включая Си и Делфи) не разрешают наследоваться больше чем от одного предка (на мой вкус - это полезное ограничение). Зато эти же языки разрешают использовать сколько угодно интерфейсов. Таким образом, когда класс реализует несколько интерфейсов он получает несколько функциональностей, к которым можно обращаться по схеме, аналогичной тому, как если бы они являлись предками класса.

Возможно, термин "наследование через интерфейс" и не соответствует всем строгим критериям термина "наследования" (хотя, по-моему - вполне соответствует). В принципе - самым важным является, действительно, не факт "наследования", а возможность обращаться унифицированно к объектам разного типа. То есть речь идёт больше о полиморфизме.

Но с точки зрения программиста, удобно (по крайней мере - мне) рассуждать об использовании интерфейсов как о наследовании общего поведения от какого-то базового элемента.

Что важно в наследовании?
Пример (буду писать на дельфи, но и сишнику, уверен, будет понятно):

Код:
var c1: TClassA; // базовый класс
var c2: TClassB; // этот клас - наследник
begin
    c1:= TClassA.create(); // это конструктор
    c2:= TClassB.create(); // это конструктор
    c1.someMethod();   // вызывается метод из TClassA
    c2.someMethod();   // вызывается метод из TClassB
    
    c1:= c2;  // присваиваем переменну типа TClassB в тип TClassA
    c1.someMethod(); // несмотря на то, что переменная c1 объявлена как TClassA - вызывается метод, объявленный в TClassB (если someMethod был объявлен как перегруженный)
end;
Это пример полиморфизма, реализованного с помощью наследования и перегрузки.

Аналогичный пример с интерфейсами:

Код:
var i1: IInterfaceA;
var i2: IInterfaceB;
var c1: TClassA;   //этот класс реализует IInterfaceA
var c2: TClassB;   //этот класс реализует IInterfaceB
var c3: TClassC;  //этот класс реализует оба интерфейса
begin
    c1:= TClassA.create();
    c2:= TClassB.create();
    c3:= TClassC.create();
    i1:= c1;
    i1.someMethod();  // вызывает реализацию метода из класса А, относящуюся к интерфейсу А
    i1:= c3;
    i1.someMethod();  // вызывает реализацию метода из класса С, относящуюся к интерфейсу А

    i2:= c2;
    i2.someMethod();  // вызывает реализацию метода из класса B, относящуюся к интерфейсу B
    i2:= c3;
    i2.someMethod();  // вызывает реализацию метода из класса С, относящуюся к интерфейсу B
end;
По внешнему виду этих 2 примеров видно, что по своему практическому поведению интерфейсы (использованные таким образом) идентичны множественному наследованию и позволяют применить те же самые приёмы программирования, что и в случае стандартного наследования.


Последний раз редактировалось Stargazer; 12.03.2009 в 23:01.