Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Abyx, Вы писали:
G>>>Альтернатива наследованию — композиция. Она показывает себя гораздо лучше. G>>>1) Нету связи между классами и требований соблюдать LSP, там где не требуется полиморфизм. A>>а чем композиция лучше приватного (множественного) наследования? S>Очевидно, тем, что она не прибита гвоздями к типу предка.
она гвоздями прибита к типу члена. в чем разница-то?
In Zen We Trust
Re[4]: Комбинаторный взрыв функциональности благодаря наследованию
Здравствуйте, Sinclair, Вы писали:
M>>Именно. Но механиз наследование тут мягко говоря не единственный и совсем не ключевой (хотя смотря в каком языке ХЗ). Может ТС работает с какмнить ЯП где только наследованием мождно делать декомпозицию ? S>Даже если и так — я по-прежнему не понимаю, каким образом наследование даст нам комбинаторный взрыв функциональности.
Пример с итераторами: есть N контейнеров, к каждому из которых есть итератор, и есть M алгоритмов на итераторах. Каждый алгоритм можно применить к каждому контейнеру, через итераторы — в итоге получается N*M возможных комбинаций, хотя написано всего O(N+M) кода.
Если, например, добавить возможность хранения в контейнерах объектов T разных типов, то получается уже N*M*T разных комбинаций при O(N+M+T) коде.
Это реализуется и через наследование+виртуальные функции, и через шаблоны, и через ФП, и даже в голом C. Это не является какой-то уникальной особенностью ООП.
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>
Здравствуйте, Аноним, Вы писали:
А>Некорректное наследование — это вредно, а корректное — один из самых мощных механизмов в программировании на сегодняшний день.
Корректное наследование, дополненное корректным агрегированием вместо некорректного наследования, даёт мощнейшую основу для написания корректных программ
(чего-то я капитанствую, да)