Адекватность использования множественного наследования
От: GarryIV  
Дата: 24.05.04 13:54
Оценка: +2 -4
Здравствуйте, Alexey Chen, Вы писали:

AC>пример 1


AC>
AC>class Kyeboard { int GetKey(); }; // реализация работы с клавиатурой
AC>class Screen { void PrintF(...); }; // реализация работы с экраном

AC>//Терминал одновременно является клавиатурой и дисплеем
AC>class Terminal : public Keyboard, public Screen {};
AC>


Руки за такое отрывать надо
Это как раз пример как НЕ надо использовать множественное наследование.

25.05.04 18:17: Ветка выделена из темы Множественное наследование : Пример
Автор: ilya_ny
Дата: 22.05.04
— Павел Кузнецов
WBR, Igor Evgrafov
Re[3]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 24.05.04 14:36
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Руки за такое отрывать надо

GIV>Это как раз пример как НЕ надо использовать множественное наследование.

Правда? А аргументы, кроме эмоций найдутся?
Re[4]: Адекватность использования множественного насле
От: Аноним  
Дата: 25.05.04 07:29
Оценка: 4 (1)
Здравствуйте, Alexey Chen, Вы писали:

AC>Правда? А аргументы, кроме эмоций найдутся?


Нужно всегда использовать, если это возможно, менее сильную зависимость между классами.
Наследование — более сильная зависимость, чем включение, а в данном случае, хватит и включения.
Наследование нужно если нужено засещать виртуальные функции, если нужен доступ к закрытым членам.
Если еще что-то не назвал, то я надеюсь, меня дополнят.
Re[4]: Адекватность использования множественного насле
От: degor Россия  
Дата: 25.05.04 08:07
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Здравствуйте, GarryIV, Вы писали:


GIV>>Руки за такое отрывать надо

GIV>>Это как раз пример как НЕ надо использовать множественное наследование.

AC>Правда? А аргументы, кроме эмоций найдутся?

Легко. Наследование используется при связи IS-A. А тут у нас Terminal HAS-A Keyboard и HAS-A Screen.
То есть надо использовать композицию:

class Terminal 
{
    Screen screen;
    Keyboard keyboard;
};
... << RSDN@Home 1.1.3 stable >>
Re[4]: Адекватность использования множественного насле
От: GarryIV  
Дата: 25.05.04 08:09
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

GIV>>Руки за такое отрывать надо

GIV>>Это как раз пример как НЕ надо использовать множественное наследование.

AC>Правда? А аргументы, кроме эмоций найдутся?


Сорри за излишнюю эмоциональнось

Аргументы не привел так как ошибка мне казалась очевидной...

В дополнение к словам Анонима могу сказать, что в поскипанном пример нарушается принцип открытия закрытия (OCP) для класса терминал. Например понадобилось к терминалу подключить другую клавиатуру — как ты это делать будешь? Кроме того у меня есть сомнения в том что это соответствует принцип подстановки Лискоу (LSP). Всегда ли терминал может быть использован как дисплей?
WBR, Igor Evgrafov
Re[5]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 08:14
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>Нужно всегда использовать, если это возможно, менее сильную зависимость между классами.

А>Наследование — более сильная зависимость, чем включение, а в данном случае, хватит и включения.
Допустим в приведенном примере вы использовали агрегирование.
Далее весь класc выглядит как делегация вызовов. Причины в том что была разорвана естественная связь is-a.
Только для того чтобы удволетворить указанному выше правилу? Кстати правило бредовое, в нем не указан тип связи классов.

А>Наследование нужно если нужено засещать виртуальные функции, если нужен доступ к закрытым членам.

А>Если еще что-то не назвал, то я надеюсь, меня дополнят.

Для наследования в смысле ОО есть очень хороший критерий. Критерий Барбары Лисков.

If for each object o1 of type S there is an object o2 of type T such that for all
programs P defined in terms of T, the behavior of P is unchanged when o1 is
substituted for o2 then S is a subtype of T.

Или в трактовке Мартина

Functions that use pointers or references to base classes
must be able to use objects of dirived classes without knowing it.

Мой пример удволетворяет этому принципу.

Теперь пример где это надо.

class Screen {
  //...
protected:
  void Assign(HANDLE_TYPE fd);
};

class Keyboard {
  // ...
protected:
  void Assign(HANDLE_TYPE fd);
};

class WindowConsole : public Screen, public Keyboard
{
  WindowConsole() {
    // открываем окно консоли и получаем хендлы ввода и вывода
    Screen::Assign(out_handle);
    Keyboard::Assign(in_handle);
  }
};


WindowConsole console;
SomeObject.PrintTo(console /* как Screen или IScreen который может реализовывать Screen */);
OtherObject.ProcessInputFrom(console /* как Keyboard или IKeyboard который может реализовывать Keyboard */);

WindowConsole есть экран и клавиатура, но при этом инициализация консоли специфична.

Теперь про наследование в смысле C++

Есть три вида наследования два из них удволетворяют критерию наследования в смысле ОО, а один нет.
1) Наследование только поведения в смысле интерфейса.
2) Наследование поведения и реализации (частичной/полной).
3) Наследование реализации но не поведения. Имеет смысл для расширения реализации через шаблонную функцию (перекрытие виртуального метода) или для адоптации класса к некому интерфейсу наследуемому публично.

Для последнего используется закрытое наследование.
Re[5]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 08:26
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Сорри за излишнюю эмоциональнось

GIV>Аргументы не привел так как ошибка мне казалась очевидной...

Для меня нет очевидной ошибки.

GIV>В дополнение к словам Анонима могу сказать, что в поскипанном пример нарушается принцип открытия закрытия (OCP) для класса терминал. Например понадобилось к терминалу подключить другую клавиатуру — как ты это делать будешь? Кроме того у меня есть сомнения в том что это соответствует принцип подстановки Лискоу (LSP). Всегда ли терминал может быть использован как дисплей?


Терминал — это конкретный класс. Это совершенно конкретный терминал XYZ1234.
Нужен другой терминал возмите класс терминала ABC54321.

Имхо ошибки на самом деле нет. Причина в догмах и критериях применимости их в данном случае.
Ит депенс.. как я написал анониму, есть точка зрения с которой то, что я написал непротиворечиво и практически оправданно.
Re[5]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 08:38
Оценка: +1
Здравствуйте, degor, Вы писали:

AC>>Правда? А аргументы, кроме эмоций найдутся?

D>Легко. Наследование используется при связи IS-A. А тут у нас Terminal HAS-A Keyboard и HAS-A Screen.
Ничем не аргументированное высказывание. С таким же успехом я могу сказать обратное.

D>То есть надо использовать композицию:

При такой точки зрения да, но я исходил из другой.
Re[5]: Адекватность использования множественного насле
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.04 08:40
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Здравствуйте, Alexey Chen, Вы писали:


GIV>>>Руки за такое отрывать надо :maniac:

GIV>>>Это как раз пример как НЕ надо использовать множественное наследование.

AC>>Правда? А аргументы, кроме эмоций найдутся?


GIV>Сорри за излишнюю эмоциональнось


GIV>Аргументы не привел так как ошибка мне казалась очевидной...


вспомни про iostream: istream, ostream

GIV>В дополнение к словам Анонима могу сказать, что в поскипанном пример нарушается принцип открытия закрытия (OCP) для класса терминал. Например понадобилось к терминалу подключить другую клавиатуру — как ты это делать будешь?


Например,понадобилось iostream перекинуть на другой файл — что делать?

GIV>Кроме того у меня есть сомнения в том что это соответствует принцип подстановки Лискоу (LSP). Всегда ли терминал может быть использован как дисплей?


всегда ли iostream может быть использован как ostream?


Все зависит от постановки задачи.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Адекватность использования множественного насле
От: GarryIV  
Дата: 25.05.04 08:58
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

А>>Нужно всегда использовать, если это возможно, менее сильную зависимость между классами.

А>>Наследование — более сильная зависимость, чем включение, а в данном случае, хватит и включения.
AC>Допустим в приведенном примере вы использовали агрегирование.
AC>Далее весь класc выглядит как делегация вызовов. Причины в том что была разорвана естественная связь is-a.
AC>Только для того чтобы удволетворить указанному выше правилу? Кстати правило бредовое, в нем не указан тип связи классов.

А>>Наследование нужно если нужено засещать виртуальные функции, если нужен доступ к закрытым членам.

А>>Если еще что-то не назвал, то я надеюсь, меня дополнят.

AC>Для наследования в смысле ОО есть очень хороший критерий. Критерий Барбары Лисков.


AC>If for each object o1 of type S there is an object o2 of type T such that for all

AC>programs P defined in terms of T, the behavior of P is unchanged when o1 is
AC>substituted for o2 then S is a subtype of T.

AC>Мой пример удволетворяет этому принципу.


Как раз тут у меня и есть сомнения. Терминал может накладываеть дополнительные ограничения на поведение дисплея и клавиатуры. В таком случае и возникнет несоответствие этому принципу.
WBR, Igor Evgrafov
Re[7]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 09:12
Оценка:
Здравствуйте, GarryIV, Вы писали:

AC>>Мой пример удволетворяет этому принципу.


GIV>Как раз тут у меня и есть сомнения. Терминал может накладываеть дополнительные ограничения на поведение дисплея и клавиатуры. В таком случае и возникнет несоответствие этому принципу.


Для того чтобы это показать, достаточно написать пример где это правило нарушется.
В приведенном мной примере этого нет, следовательно при таком способе использования (архитектуре) это правило выполняется и отношение между классами is-a.

Мало того, я не вижу в чем вообще есть проблема в таком подходе, при заданном способе использованиея. Еще раз напомню, что Terminal — это конкретный класс с совершенно конкретной клавиатурой и совершенно конкретным экраном. Keyboard и Screen — это конкретные классы. Для соблюдения DIP можно реализовать в классах Keyboard и Screen соответсвующие интерфейсы, но к топику это отношения не имеет, по тому и было опущено.
Re[6]: Адекватность использования множественного насле
От: GarryIV  
Дата: 25.05.04 09:13
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

GIV>>В дополнение к словам Анонима могу сказать, что в поскипанном пример нарушается принцип открытия закрытия (OCP) для класса терминал. Например понадобилось к терминалу подключить другую клавиатуру — как ты это делать будешь? Кроме того у меня есть сомнения в том что это соответствует принцип подстановки Лискоу (LSP). Всегда ли терминал может быть использован как дисплей?


AC>Терминал — это конкретный класс.

AC>Это совершенно конкретный терминал XYZ1234.
AC>Нужен другой терминал возмите класс терминала ABC54321.

Разве это оправдано? Зачем такие сильные ограничения когда использование агрегирования позволяем менять клавиатуры и дисплеи терминала так что это останется незаметно для пользователей класса терминал?
WBR, Igor Evgrafov
Re[7]: Адекватность использования множественного насле
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.04 09:18
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Здравствуйте, Alexey Chen, Вы писали:


GIV>>>В дополнение к словам Анонима могу сказать, что в поскипанном пример нарушается принцип открытия закрытия (OCP) для класса терминал. Например понадобилось к терминалу подключить другую клавиатуру — как ты это делать будешь? Кроме того у меня есть сомнения в том что это соответствует принцип подстановки Лискоу (LSP). Всегда ли терминал может быть использован как дисплей?


AC>>Терминал — это конкретный класс.

AC>>Это совершенно конкретный терминал XYZ1234.
AC>>Нужен другой терминал возмите класс терминала ABC54321.

GIV>Разве это оправдано? Зачем такие сильные ограничения когда использование агрегирования позволяем менять клавиатуры и дисплеи терминала так что это останется незаметно для пользователей класса терминал?


да потому что терминал предоставляет пользователю интерфейс дисплея и интерфейс клавиатуры.
Вот и все.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 09:41
Оценка:
Здравствуйте, GarryIV, Вы писали:

AC>>Терминал — это конкретный класс.

AC>>Это совершенно конкретный терминал XYZ1234.
AC>>Нужен другой терминал возмите класс терминала ABC54321.

GIV>Разве это оправдано? Зачем такие сильные ограничения когда использование агрегирования позволяем менять клавиатуры и дисплеи терминала так что это останется незаметно для пользователей класса терминал?


Слишком гибкий код это тоже плохо.
Агрегирование это другой вариант решения этой задачи и есть случаи когда оно будет более удобно.
Когда терминал рассматривается как некий код упровляющий хендлами ввода/вывода, то клавиатуры и дисплеи не меняются, меняется инициализатор и финализатор. Все зависит от точки зрения и способов использования, а полностью абстратная архитектура бессмыслена, потому как не решает какой либо задачи.

Вопрос был о наследовании, я привел непротиворечивый и практически применимый пример.
Если спор, что лучше, то это бессмысленный спор. Это зависит от задачи.
Если спор о том надо ли отрывать за такой код что либо, хм ... думаю, что это неправильная формулировка причины для спора.
Re[8]: Адекватность использования множественного насле
От: GarryIV  
Дата: 25.05.04 09:44
Оценка: 9 (1)
Здравствуйте, Alexey Chen, Вы писали:

AC>>>Мой пример удволетворяет этому принципу.


GIV>>Как раз тут у меня и есть сомнения. Терминал может накладываеть дополнительные ограничения на поведение дисплея и клавиатуры. В таком случае и возникнет несоответствие этому принципу.


AC>Для того чтобы это показать, достаточно написать пример где это правило нарушется.

AC>В приведенном мной примере этого нет, следовательно при таком способе использования (архитектуре) это правило выполняется и отношение между классами is-a.

Пожалуйста пример Причем из реальной жизни моего компьютера (чем он не терминал )

По кнопке ScrollLock у меня показывается\прячется диалог поиска (и соответственно зажигается светоид). Если нажать Esc при активном диалоге то он пропадает и светоид гаснет.

То есть нажетие Esc в определенный момент времени приводит к гашению светоида ScrollLock чего пользователь класса Keyboard никак не может ожидать. Именно такое поведение и нарушает LSP.


class Keyboard
{
 protected:
  virtual void OnKeyPress(int key)
  {
    switch(key)
    {
     case SCROLL_LOCK:
       SetScrollLockLedState(!scrollLockLedState;)
       break;
    }
  }
}

class Terminal : public Keyboard
{
 protected:
  
  virtual void OnKeyPress(int key)
  {
    Keyboard::OnKeyPress(key);
    switch(key)
    {
     case ESC:
       if(dialog->Active)
       {
         dialog->Hide();
         SetScrollLockLedState(false);
       }
       break;
    }      
}



AC>Мало того, я не вижу в чем вообще есть проблема в таком подходе, при заданном способе использованиея. Еще раз напомню, что Terminal — это конкретный класс с совершенно конкретной клавиатурой и совершенно конкретным экраном.


Конкретный так конкретный — роли тут это не играет.
WBR, Igor Evgrafov
Re[9]: Адекватность использования множественного насле
От: Alexey Chen Чили  
Дата: 25.05.04 10:10
Оценка: 8 (1) +1
Здравствуйте, GarryIV, Вы писали:

GIV>Здравствуйте, Alexey Chen, Вы писали:


GIV>Пожалуйста пример Причем из реальной жизни моего компьютера (чем он не терминал )


GIV>По кнопке ScrollLock у меня показывается\прячется диалог поиска (и соответственно зажигается светоид). Если нажать Esc при активном диалоге то он пропадает и светоид гаснет.


GIV>То есть нажетие Esc в определенный момент времени приводит к гашению светоида ScrollLock чего пользователь класса Keyboard никак не может ожидать. Именно такое поведение и нарушает LSP.

Как оно его нарушает? Посмотрите класс Keyboard в оригинальном примере и скажите где ошибка. То есть, что именно нарушается?
Каким образом это влияеет на наследование и почему это плохо?
Кстати, а почему он не ожидает ее нажатия (хоть к вопросу это никакого отношения и не имеет)?
Наверно, потому что приложене не сферическое в вакууме, а совершенно конкретное и ему эта кнопка нафиг не нужна.

А если пользователь нажмет кнопку выключения питания? Она на клавиатуре тоже иногда бывает, а еще там бывает управление CD плеером и микшером.
Я уже сказал про применимость архитектуры в условиях задачи и бессмысленность абстрактной архитектуры.

GIV>[ccode]

GIV>class Keyboard
GIV>{
GIV> protected:
GIV> virtual void OnKeyPress(int key)
GIV> {
GIV> switch(key)
GIV> {
GIV> case SCROLL_LOCK:
GIV> SetScrollLockLedState(!scrollLockLedState
GIV> break;
GIV> }
GIV> }
GIV>}

По мойму мы о разных вещах. Просто совершенно разных.
Очередной способ свести оригинальный вариант к идеотизму и сказать что так оно и было.

Сорри, но дальше я в таком ключе общаться не буду, надоело уже.
Re[10]: Адекватность использования множественного насл
От: Mnmal  
Дата: 25.05.04 11:47
Оценка:
Здравствуйте, Alexey Chen, Вы писали:

AC>Я уже сказал про применимость архитектуры в условиях задачи и бессмысленность абстрактной архитектуры.


AC>По мойму мы о разных вещах. Просто совершенно разных.

AC>Очередной способ свести оригинальный вариант к идеотизму и сказать что так оно и было.

AC>Сорри, но дальше я в таком ключе общаться не буду, надоело уже.


зря вы так бурно реагируете, ИМХО.
есть некие правила хорошей архитектуры, которые де факто уже стали стандартом.
И как видно из ваших же комментариев вы в них разбираетесь (я имею ввиду GoF, работы Саттера, Александреску и пр.)
Не понятно только почему на практике не применяете, по крайней мере в указанном примере

А аргументация про применимость архитектуры к задаче сродни "ну и так же все работает".
В С++ практически любую задачу можно решить множеством способов, в том числе и разных архитектурно,
но лучше все таки это делать красиво

А множественное наследование реализации дейтвительно нужно применять аккуратно,
практически всегда вместо него оправданней использовать мн. наследование интерфейсов или шаблоные классы.

В конце концов чем меньше зависимость менжду классами тем меньше времени придется тратить на компиляцию, при незначительных исправлениях. А в больших системах это ох как решает.
Re[9]: Адекватность использования множественного насле
От: jazzer Россия Skype: enerjazzer
Дата: 25.05.04 11:57
Оценка:
Здравствуйте, GarryIV, Вы писали:

GIV>Здравствуйте, Alexey Chen, Вы писали:


AC>>>>Мой пример удволетворяет этому принципу.


GIV>>>Как раз тут у меня и есть сомнения. Терминал может накладываеть дополнительные ограничения на поведение дисплея и клавиатуры. В таком случае и возникнет несоответствие этому принципу.


AC>>Для того чтобы это показать, достаточно написать пример где это правило нарушется. :)

AC>>В приведенном мной примере этого нет, следовательно при таком способе использования (архитектуре) это правило выполняется и отношение между классами is-a.

GIV>Пожалуйста пример :) Причем из реальной жизни моего компьютера (чем он не терминал :))) )


GIV>По кнопке ScrollLock у меня показывается\прячется диалог поиска (и соответственно зажигается светоид). Если нажать Esc при активном диалоге то он пропадает и светоид гаснет.


GIV>То есть нажетие Esc в определенный момент времени приводит к гашению светоида ScrollLock чего пользователь класса Keyboard никак не может ожидать. Именно такое поведение и нарушает LSP.


Вы неверно понимаете этот принцип.
Ваш пример никоим образом не демонстрирует нарушения LSP.

Какие методы предоставляет класс Keyboard?
Нечто вроде press_key, release_key, get_light.
Если ты с этими методами подойдешь к терминалу, ничего не изменится по сравнению с любой другой клавиатурой — клавиши нажимаются, отпускаются, статусы светодиодов узнать можно.
Принцип подстановки в действии.


грубо говоря, можно написать следующий алгоритм:
пройтись по комнате, на каждой попавшейся клавиатуре набирая "print password"
пройтсь по комнате еще раз, на каждом попавшемся дисплее прочитать, что там написано:
// pseudocode
for_each(keyboards.begin(), keyboards.end(), _1->type_string("print password"));
accumulate(displays.begin(), displays.end(), _1->get_text);

Как видите, терминал может находиться в обоих контейнерах, и программа будет совершенно валидной.
Принцип подстановки нигде не нарушается
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[11]: Адекватность использования множественного насл
От: Alexey Chen Чили  
Дата: 25.05.04 12:47
Оценка: 1 (1)
Здравствуйте, Mnmal, Вы писали:

AC>>Сорри, но дальше я в таком ключе общаться не буду, надоело уже.

M>зря вы так бурно реагируете, ИМХО.

Может быть. Но "правильные чуваки" постоянно пытаются наставить меня на "путь истинный", применяя способ сведения моего примера к чему-то к оригиналу не относящемуся, после чего говорится — ну вот видите. После этого совершенно не хочется отвечать на чьи-то вопросы и помогать кому-то. Просто не понятно как обьяснить человеку, что это ну совсем не то.

M>есть некие правила хорошей архитектуры, которые де факто уже стали стандартом.

M>И как видно из ваших же комментариев вы в них разбираетесь (я имею ввиду GoF, работы Саттера, Александреску и пр.)
M>Не понятно только почему на практике не применяете, по крайней мере в указанном примере

А оно там надо?

Указанный пример демонстрирует один из способов решения конкретной проблемы где можно использовать множественное наследование. Кроме догматических утверждений, что так плохо и примеров относящихся совершенно к другому, я аргументов против не увидел.

В любом случае, ограничение стериотипами и догматами вещь конечно хорошая, для начала, но на определенном этапе нчинает сильно усложнять жизнь.

M>А аргументация про применимость архитектуры к задаче сродни "ну и так же все работает".

А где был такй агрумент? Как говорил один из моих учителей — "жопой чуствую — это не аргумент".

M>В конце концов чем меньше зависимость менжду классами тем меньше времени придется тратить на компиляцию, при незначительных исправлениях. А в больших системах это ох как решает.


Блин, меня жутко удивляет, когда на простой пример набрсываются "типа курутые мужики", что вот в больших системах..... Большие системы, между прочим, строятся из маленьких блоков. Люди знающие, что такое большая система, даже не подумают здесь приводить ее как аргумент. Это просто из другой оперы.

— А вот у нас на таити.....
— Нас и здесь неплохо кормят!
Re[12]: Адекватность использования множественного насл
От: Alexey Chen Чили  
Дата: 25.05.04 12:58
Оценка:
M>>А аргументация про применимость архитектуры к задаче сродни "ну и так же все работает".

А, понял о чем это. Нет не сродни. Это совершенно разные вещи.

То есть вы хотите сказать, что архитектура существует сама по себе? Без задачи для решения которой она создается? Интерсный взгляд. Хотя, я придерживаюсь другой точки зрения.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.