Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Проблема наследования в том, что вместо _потенциального_ комбинаторного взрыва функциональности, оно практически _гарантированно_ дает комбинаторный взрыв сложности.
Комбинаторный взрыв функциональности благодаря наследованию
Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
В этом и заключается польза наследования и создания иерархий. Просто в массовом сознании бытует мысль о "вредности" наследования. Лично я, например, никогда, за всю свою карьеру, не сталкивался с проблемами, вызванными наследованием. Я видел, как другие делают некорректное наследование (нарушающее логику взаимоотношений между понятиями предметной области), но некорректность является проблемой где угодно.
Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль,
не, не очень понятна. А> и если да, то согласны ли вы с ней
Так что не очень согласен. А>, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Откуда вдруг мы получим комбинаторный взрыв функциональности? Мне что-то никакие примеры в голову не приходят.
Вот ткните пальцем в Foundation Class Library — где там именно наследование приводит к "комбинаторному взрыву"?
Я понимаю, что функциональная декомпозиция приводит к комбинаторному взрыву. К примеру, отделение TextReader от Stream позволяет нам не морочиться с кодировками на уровне файловых, сетевых, и прочих потоков.
А вот, к примеру, попытка отнаследоваться от StreamReader для того, чтобы научиться отслеживать текущую строку/колонку — явный тупик, и ни к какому комбинаторному взрыву не приводит. Потому что ни к каким другим ридерам эта функциональность неприменима, в отличие от композиции — когда мы наследуемся от TextReader и оборачиваем внешний TextReader (см. тж. паттерн Декоратор).
С этой точки зрения наследование безусловно вредно. Вся польза от наследования TextReader по сравнению с реализацией ITextReader — в предоставленных реализациях по умолчанию. Оставить в ITextReader только ReadChar — создать неудобства пользователям и ограничить производительность кода; запихать туда все ReadXXX — потребовать слишком многого от реализатора. Вот тут наследование в самый раз — сколько методов хочешь, столько и перегружай. Можно взлететь с одним ReadChar, а потом оптимизировать ReadLine и прочие по мере желания.
Но эти преимущества никакого отношения к экспоненциальному взрыву не имеют, это всего лишь небольшие удобства.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Это относится к любому полиморфизму с грамотной абстракцией, а не только к наследованию+виртуальным функциям.
Канонический пример — M контейнеров и N алгоритмов. Если делать в лоб — то для покрытия всего алгоритмического пространства нужно сделать M*N алгоритмов, но если добавить итераторы — достаточно реализовать N алгоритмов + M итераторов.
В C++ STL (стандартные алгоритмы и контейнеры) для полиморфизма никакое наследование не используется — и при этом STL это лучшая библиотека в своём роде.
А>В этом и заключается польза наследования и создания иерархий. Просто в массовом сознании бытует мысль о "вредности" наследования. Лично я, например, никогда, за всю свою карьеру, не сталкивался с проблемами, вызванными наследованием. Я видел, как другие делают некорректное наследование (нарушающее логику взаимоотношений между понятиями предметной области), но некорректность является проблемой где угодно. А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
А>В этом и заключается польза наследования и создания иерархий. Просто в массовом сознании бытует мысль о "вредности" наследования. Лично я, например, никогда, за всю свою карьеру, не сталкивался с проблемами, вызванными наследованием. Я видел, как другие делают некорректное наследование (нарушающее логику взаимоотношений между понятиями предметной области), но некорректность является проблемой где угодно.
А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Чушь какая-то честно говоря. Слишком много книг по ООАД читали видимо.
Почему наследование плохо:
1) Наследование должно удовлетворять LSP, это сильно ограничивает ту мощность, о которой вы пишите. Вполне возможно что множественное наследование, для которого не требуется удовлетворять LSP является мощным средством, но тогда не будет полиморфизма (из-за которого и есть смысл ООП).
2) Наследование создает слишком сильную связь межу наследником и родителем. Чтобы не поломать наследников надо крайне внимательно вносить изменения в базовый класс. Это называется хрупкий базовый класс. Даже есть OCP, который рекомендует не менять классы вообще, но это ведет к комбинаторному взрыву костылей, а не функциональности.
Альтернатива наследованию — композиция. Она показывает себя гораздо лучше.
1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм.
2) Используя рекурсивную композицию можно построить гораздо более сложные структуры, чем наследованием.
Вообще есть мнение, что наследование реализации не нужно вообще и оно легко может быть заменено наследованием интерфейсов и композицией.
Здравствуйте, Аноним, Вы писали:
А>М-да, что-то уровень дискуссии на этом сайте слабоват. Аргументы какие-то совсем невнятные, даже отвечать неинтересно.
Если тебе непонятны какие-то аргументы — задавай дополнительные вопросы. Если убрать BS вида "аргументы невнятные, отвечать неинтересно" — то тебе обязательно ответят, на этом сайте есть очень толковые специалисты.
Re[3]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Abyx, Вы писали:
G>>Альтернатива наследованию — композиция. Она показывает себя гораздо лучше. G>>1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм. A>а чем композиция лучше приватного (множественного) наследования?
Очевидно, тем, что она не прибита гвоздями к типу предка.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
M>>Именно. Но механиз наследование тут мягко говоря не единственный и совсем не ключевой (хотя смотря в каком языке ХЗ). Может ТС работает с какмнить ЯП где только наследованием мождно делать декомпозицию ? S>Даже если и так — я по-прежнему не понимаю, каким образом наследование даст нам комбинаторный взрыв функциональности.
Пример с итераторами: есть N контейнеров, к каждому из которых есть итератор, и есть M алгоритмов на итераторах. Каждый алгоритм можно применить к каждому контейнеру, через итераторы — в итоге получается N*M возможных комбинаций, хотя написано всего O(N+M) кода.
Если, например, добавить возможность хранения в контейнерах объектов T разных типов, то получается уже N*M*T разных комбинаций при O(N+M+T) коде.
Это реализуется и через наследование+виртуальные функции, и через шаблоны, и через ФП, и даже в голом C. Это не является какой-то уникальной особенностью ООП.
Re: Комбинаторный взрыв функциональности благодаря наследованию
любая факторизация кода дает комбинаторный взрыв, при чем тут наследование..
Re: Errata
От:
Аноним
Дата:
08.12.13 09:23
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Читать: "классов и методов".
Re[2]: Комбинаторный взрыв функциональности благодаря наследованию
От:
Аноним
Дата:
08.12.13 09:33
Оценка:
Здравствуйте, dilmah, Вы писали:
D>любая факторизация кода дает комбинаторный взрыв, при чем тут наследование..
Если мы говорим о статической типизации без наследования, то, вроде как, нет. Набор функций, написанных для одного типа, не дает никакой функциональности для вновь созданного типа, даже если эти два типа концептуально родственны (если только не написать делегирурующие обертки вручную).
Если говорить о динамической типизации, то, фактически, это разновидность полиморфизма, на котором можно построить структуру, аналогичную наследованию, так что это эквивалентная задача.
Re: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали: А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Александреску на эту трему в начале своей книги рассуждает
с наследованием плохо то, что люди не умеют его использовать обычно и увеличивают связность кода без всякой причины
например, у нас есть задача — мы получаем данные от пользователя, валидируем данные, выводим ошибки, если они есть, собираем в хитрую структуру, отправляем на сервер, обновляем UI в зависимости от результата. и так несколько действий, отличающихся деталями валидации или собирания в структуру.
как это сделать неправильно? пишщется один класс, который все это делает, от него наследуются классы, где подменяется реализация некоторых ф-ий на кастомные.
после этого менять реализацию каждой отдельной операции почти невозможно — связность слишком большая.
вместо этого надо разбить идею не на функции, а на классы, каждый из которых делает свое single responsibility — один валидирует, другой выводит ошибки, третий собирает в структуру, четвертый работает с сервером, пятый обновляет UI и уже параметризуя эти классы, можно составлять из них композицию — нужное нам действие. кажое действие будет полностью независимо от другого.
Re[2]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали:
А> Некорректное наследование — это вредно, а корректное — один А> из самых мощных механизмов в программировании на сегодняшний день.
рассмотрим базовый http-сервер, входящий в библиотеку. допустим, нам нужно менять штатные обработчики на кастомные. как это сделать? например, унаследовать производный класс от базового или без всякого ООП тупо использовать каллбаки. с определенной вероятностью откомпилированный код будет практически идентичным, ибо наследование реализуется через таблицу виртуальных функций, которую можно замутить без наследования.
о каком взрыве функциональности вы говорите? если на то пошло, то механизмы, обеспечивающие итеграцию одного языка в другой, намного более мощные. скажем, на си можно вызвать питон, а из питона код на жабе, а из жабы код на питоне, при этом питону доступны все библиотеки на жабе и наоборот с минимальным оверхидом, который обеспечивается за счет того, что питон компилируется в байт-код на джаве и потому с точки зрения жабы выглядит очень даже нативно.
это настоящий взрыв функциональности. вам становятся доступными все вкусности всех языков программирования сразу. причем, такой прием уже давно используется в тех же играх, где игровая физика пишется на плюсах, а игровая логика на питоне.
идем дальше. когда мы программируем на смеси языков, то крайне желательно придерживаться принципа наименьших сущностей. если в языке А есть множественное наследование, а в языке Б его нет, то лучше писать без него, иначе крышу сносит.
да и вообще... даже правильная декомпозиция на уровне процедурного программирования -- БОЛЬШАЯ РЕДКОСТЬ. народ пишет функции на 1000 строк и одна функция решает множество задач. далеко не сразу приходит понимание, что вместо одной функции на 1000 строк лучше написать 100 функций по 10 строк, т.к. в этом случае на самом верхнем уровне абстракции мы получаем легко читаемый английский текст, а в остальные функции углубляться нет смысла, т.к. их действие вытекает из их названия.
правильная декомпозиция с наследованием предъявляет к программисту намного более суровые требования, а цена ошибок резко возрастает. код утрачивает гибкость и становится совсем непонятным. причем, жизненно необходимые функции у нас оказываются захардкорены. простой пример -- загрузить файл в память и что-то такое с ним сотворить. очевидно, что нам нужны функции взять байт/записать байт (слово, двойное слово с учетом порядка байт). если обращение к памяти осуществляется через вот такие вот функции, то код получается портабельным и расширяемым. возникла потребность работать с файлами, которые сильно больше имеющейся памяти -- будем грузить файл кусками, при необходимости организуя кэш. и все это совершенно прозрачно для остальных функций. а если файл мааааленький, то эти функции вырождаются в прямое обращение к памяти. как-то так. но в жизни оказывается, что файл читается в буфер и об этом буфере знает вся шобла иерархий классов. дурдом. а вы говорите наследование...
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали: А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Корни наследования идут от одного абстраткого типа данных, когда углубляясь в иерархию этот тип специфицируется и уточняется. По моему мнению в этом и тольо в этом случае можно рассматривать применение наследоания, т.к. это единственно правльное его применение.
Во всех остальных случаях это, скорее всего, будет неправльно.
Re[2]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
S>А вот, к примеру, попытка отнаследоваться от StreamReader для того, чтобы научиться отслеживать текущую строку/колонку — явный тупик, и ни к какому комбинаторному взрыву не приводит.
Дополню — наследование и не должно приводить к "взрыву функциональности", по крайней мере если не нарушать LSP.
Re: Комбинаторный взрыв функциональности благодаря наследованию
S>Я понимаю, что функциональная декомпозиция приводит к комбинаторному взрыву.
Именно. Но механиз наследование тут мягко говоря не единственный и совсем не ключевой (хотя смотря в каком языке ХЗ). Может ТС работает с какмнить ЯП где только наследованием мождно делать декомпозицию ?
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, gandjustas, Вы писали:
G>Альтернатива наследованию — композиция. Она показывает себя гораздо лучше. G>1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм.
а чем композиция лучше приватного (множественного) наследования?
In Zen We Trust
Re[3]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, minorlogic, Вы писали: M>Именно. Но механиз наследование тут мягко говоря не единственный и совсем не ключевой (хотя смотря в каком языке ХЗ). Может ТС работает с какмнить ЯП где только наследованием мождно делать декомпозицию ?
Даже если и так — я по-прежнему не понимаю, каким образом наследование даст нам комбинаторный взрыв функциональности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Abyx, Вы писали:
G>>>Альтернатива наследованию — композиция. Она показывает себя гораздо лучше. G>>>1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм. A>>а чем композиция лучше приватного (множественного) наследования? S>Очевидно, тем, что она не прибита гвоздями к типу предка.
она гвоздями прибита к типу члена. в чем разница-то?
In Zen We Trust
Re[5]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Abyx, Вы писали: A>она гвоздями прибита к типу члена. в чем разница-то?
C чего это вы взяли? Правильная композиция — она по ссылке, а не по значению.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Комбинаторный взрыв функциональности благодаря наследованию
EP>Пример с итераторами: есть N контейнеров, к каждому из которых есть итератор, и есть M алгоритмов на итераторах. Каждый алгоритм можно применить к каждому контейнеру, через итераторы — в итоге получается N*M возможных комбинаций, хотя написано всего O(N+M) кода. EP>Если, например, добавить возможность хранения в контейнерах объектов T разных типов, то получается уже N*M*T разных комбинаций при O(N+M+T) коде.
Это всё понятно. Непонятно, при чём тут наследование. На всякий случай напомню, что ни контейнеры, ни итераторы, ни хранимые типы в STL никакими отношениями наследования не связаны. А там, где связаны (например, в Java), никакого комбинаторного взрыва нет. EP>Это реализуется и через наследование+виртуальные функции, и через шаблоны, и через ФП, и даже в голом C. Это не является какой-то уникальной особенностью ООП.
Вот как раз жестокий юмор — в том, что реализовывать ваш пример при помощи одного лишь наследования — это просто копец убиться об стену.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
S>Это всё понятно. Непонятно, при чём тут наследование. На всякий случай напомню, что ни контейнеры, ни итераторы, ни хранимые типы в STL никакими отношениями наследования не связаны.
.
S>А там, где связаны (например, в Java), никакого комбинаторного взрыва нет.
Тем не менее подобная концепция реализуется через чистое ООП в виде абстрактных классов и наследование (без шаблонов и дженериков).
EP>>Это реализуется и через наследование+виртуальные функции, и через шаблоны, и через ФП, и даже в голом C. Это не является какой-то уникальной особенностью ООП. S>Вот как раз жестокий юмор — в том, что реализовывать ваш пример при помощи одного лишь наследования — это просто копец убиться об стену.
Да — там будет больше runtime dispatch'а, да — нужны будут cast'ы, да — наследование делает классы более "закостенелыми".
Но всё равно, всё необходимое что нужно для получения N*M функциональности через O(N+M) код — это полиморфизм, который есть и в ООП.
Другое дело, что это не какая-та уникальная фича наследования — и доступно через другие средства.
Re[6]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Abyx, Вы писали: A>>она гвоздями прибита к типу члена. в чем разница-то? S>C чего это вы взяли? Правильная композиция — она по ссылке, а не по значению.
в плюсах — тоже не прибита гвоздями. Там можно наследоваться от шаблонного параметра. Другое дело, что при композиции мы можем менять фактический тип объекта в ран-тайм, а в случае шаблонов — только в компил тайм. Но ран-тайм не всегда лучше компил тайма.
Re[7]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Тем не менее подобная концепция реализуется через чистое ООП в виде абстрактных классов и наследование (без шаблонов и дженериков).
А также подобная концепция реализуется через ограниченное ООП в виде интерфейсов и классов, без наследования реализации вообще.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали:
А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Если речь идёт о наследовании реализации, то это всего лишь одна из более продвинутых техник повторного использования кода.
А вообще в программировании на сегодняшний день в плане функциональности самые мощные механизмы перенимаются из функционального программирования. ООП имеет к функциональности отношение лишь как компоновщик, сборщик функциональности в более крупные компоненты, чем просто функции и методы.
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
G>>Альтернатива наследованию — композиция. Она показывает себя гораздо лучше. G>>1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм. A>а чем композиция лучше приватного (множественного) наследования?
Ничем, это практически тоже самое. Даже layout совпадает у классов вида:
class X: private A, private B, private C {}
class Y {
private:
A a;
B b;
C c;
}
Только связь при наследовании слишком сильная, это создает проблему хрупкого базового класса.
Re[4]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, gandjustas, Вы писали:
G>Ничем, это практически тоже самое. Даже layout совпадает у классов вида:
G>
G>class X: private A, private B, private C {}
G>class Y {
G> private:
G> A a;
G> B b;
G> C c;
G>}
G>
G>Только связь при наследовании слишком сильная, это создает проблему хрупкого базового класса.
чем связь с приватным базовым классом сильнее связи с приватным членом?
чем хрупкий базовый класс отличается от хрупкого члена?
чем this.foo() отличаеся от m_a.foo() ?
In Zen We Trust
Re[5]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
G>>Ничем, это практически тоже самое. Даже layout совпадает у классов вида:
G>>
G>>class X: private A, private B, private C {}
G>>class Y {
G>> private:
G>> A a;
G>> B b;
G>> C c;
G>>}
G>>
G>>Только связь при наследовании слишком сильная, это создает проблему хрупкого базового класса.
A>чем связь с приватным базовым классом сильнее связи с приватным членом?
Ну например нельзя просто так взять добавить метод в базовый класс.
A>чем хрупкий базовый класс отличается от хрупкого члена?
Хрупкий член это наверное половая болезнь...
A>чем this.foo() отличаеся от m_a.foo() ?
Тем что за m_a при желании может стоять любая реализация, а this.foo() привязывается по время компиляции.
Пример простой:
Был Класс MyController, который использовал MyService. Этот же MyService был использован в 10 других классах.
Потом появился NewMyService: MyService, который используется в NewMyController:MyController. А потом от наследника NewMyController отказались и начали подсовывать нужную реализацию через IoC.
Если бы в схеме использовалось наследование, то ничего хорошего бы не вышло.
Re[6]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, gandjustas, Вы писали:
A>>чем связь с приватным базовым классом сильнее связи с приватным членом? G>Ну например нельзя просто так взять добавить метод в базовый класс.
почему нельзя?
struct Base {
void a() { printf("a"); }
+ void b() { printf("b"); }
};
struct Some : private Base {
void do_a() { this->a(); }
};
взял и добавил новый метод b. никто ничего и не заметил.
A>>чем this.foo() отличаеся от m_a.foo() ? G>Тем что за m_a при желании может стоять любая реализация,
а может и не любая. в С++ у "A a;" вполне конкретная реализация, а не "любая". G>а this.foo() привязывается по время компиляции.
G>Пример простой: G>Был Класс MyController, который использовал MyService. Этот же MyService был использован в 10 других классах. G>Потом появился NewMyService: MyService, который используется в NewMyController:MyController. А потом от наследника NewMyController отказались и начали подсовывать нужную реализацию через IoC. G>Если бы в схеме использовалось наследование, то ничего хорошего бы не вышло.
т.е. с наследованием было бы в начале
class MyController : public AbstractController, private MyService {};
class MyController1 : private MyService {};
...
class MyController10 : private MyService {};
а потом сделали бы
class NewMyController : public AbstractController, private NewMyService {};
и в чем проблема? и зачем IoC?
In Zen We Trust
Re: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Аноним, Вы писали:
А>Понятна ли вам мысль, и если да, то согласны ли вы с ней, что основное преимущество наследования заключается в том, что при адекватном применении в сочетании с полиморфизмом оно дает комбинаторный взрыв функциональности, то есть добавление новых классов и объектов дает непропорционально большой прирост общей функциональности иерархии классов?
Нет, в этом заключается ее основной недостаток.
Новая функциональнисть из ничего не возникнет. Новая функциональность — это когда программа делает что-то новое и полезное. Новое и полезное за вас никто автоматически не нагенерирует. А вот хаос, он в "умелых" руках действительно возрастает в геометрической прогрессии.
Re[7]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, gandjustas, Вы писали:
A>>>чем связь с приватным базовым классом сильнее связи с приватным членом? G>>Ну например нельзя просто так взять добавить метод в базовый класс.
A>почему нельзя?
A>
A> struct Base {
A> void a() { printf("a"); }
A>+ void b() { printf("b"); }
A> };
A> struct Some : private Base {
A> void do_a() { this->a(); }
A> };
A>
A>взял и добавил новый метод b. никто ничего и не заметил.
А если уже есть метод b в Some?
А если класс Some является предком класса Some1 и Base тоже является?
A>>>чем this.foo() отличаеся от m_a.foo() ? G>>Тем что за m_a при желании может стоять любая реализация, A>а может и не любая. в С++ у "A a;" вполне конкретная реализация, а не "любая".
Это детали конкретного синтаксиса конкретного языка.
G>>Пример простой: G>>Был Класс MyController, который использовал MyService. Этот же MyService был использован в 10 других классах. G>>Потом появился NewMyService: MyService, который используется в NewMyController:MyController. А потом от наследника NewMyController отказались и начали подсовывать нужную реализацию через IoC. G>>Если бы в схеме использовалось наследование, то ничего хорошего бы не вышло.
A>т.е. с наследованием было бы в начале
A>
Здравствуйте, Аноним, Вы писали:
А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Корректное наследование, дополненное корректным агрегированием вместо некорректного наследования, даёт мощнейшую основу для написания корректных программ
(чего-то я капитанствую, да)