В первом случае – мы будем использовать только одну из копий объекта A. Вторая
копия у нас просто «повиснет» и программа в целом может работать неверно, т.к.
класс B ничего не знает о том, что его предок не используется. Т.е. вторая копия
подобъекта A никак не будет использоваться, но будет занимать память. Во втором
варианте – просто выполняется дублирование операций, и как следствие возникает
необходимость поддерживать синхронность обоих подобъектов типа A. Это плохой
стиль и рассадник всевозможных ошибок.
Эти рассуждения вне контекста конкретной иерархии классов и ее функциональности
бессмысленны. Тем не менее выводы довольно категоричны и однозначты.
Кстати про виртуальное наследование:
давно интересуют примеры его использования в реальных программах.
Пока единственное, что я видел — это пример из STL:
template <class Elem, class Tr = char_traits<Elem> >
class basic_istream
: virtual public basic_ios<Elem, Tr>
Так же на форуме приводился пример со счётчиком экземпляров класса.
Честно говоря, создаётся впечатление, что это очень сомнительная фича C++...
Здравствуйте, Аноним, Вы писали: А>Так же на форуме приводился пример со счётчиком экземпляров класса. А>Честно говоря, создаётся впечатление, что это очень сомнительная фича C++...
Если есть множественное наследование, то должно быть и виртуальное. А зачем нужно множественное? да затем что и простое.
Кстати и без простого можно и обойтись
Здравствуйте, Programador, Вы писали:
P>Если есть множественное наследование, то должно быть и виртуальное. А зачем нужно множественное? да затем что и простое. P>Кстати и без простого можно и обойтись P>
P>struct B
P>{ int x,y;
P>};
P>struct D
P>{ B B;
P> int z;
P>};
P>
Без наследования можно обойтись. И даже нужно, полностью сохраняя при этом идею полиморфизма. Но не в C++, Java, C# и тому подобных. Сама идея наследования как расширения функциональности является глубоко порочной и противоречит сущности нашего мира. Особенный LOL вызывают попытки порождения производных классов от std::string, std::vector<MyType> и тому подобных. Наследование должно быть только специализацией функциональности и ничем более. Короче, нет виртуальных функций в базовом классе? — наследование запрещено. Вот так должно быть IMSO. Но тогда это уже и не наследование получается, а некая динамическая специализация. А тот беспредел, что сейчас имеется, в конечном итоге приводит к обилию нелепых конструкций, типа ((my_string*)&std_str)->my_compare_with(b);
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
MS>Сама идея наследования как расширения функциональности является глубоко порочной и противоречит сущности нашего мира.
А как же ООП иерархии?
Скажем такая:
предмет мебели
предмет мебели, на котором сидят
кресло
MS>Но тогда это уже и не наследование получается, а некая динамическая специализация. А тот беспредел, что сейчас имеется, в конечном итоге приводит к обилию нелепых конструкций, типа ((my_string*)&std_str)->my_compare_with(b);
А может лучше научиться нормально программировать? Хотя я согласен, что в функциональном языке наследование смотрится чужеродно. Ну так ведь C++ он же мультипарадигменный, или как там это зовут нынче?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, McSeem2, Вы писали:
MS>Ясно же было сказано — если нет необходимости в использовании витруальных функций, то нет и ни малейшего смысла в этой иерархии.
Да? А почему? Почему я не могу, например, иметь список предметов мебели в комнате, особенно если у каждого из них прописан тип, в виде аттрибута?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>Кстати про виртуальное наследование: А>давно интересуют примеры его использования в реальных программах.
Есть вот такой баян, запрещающий наследование от определенного класса:
class Final;
class FinalHelper
{
friend class Final;
private:
FinalHelper() { }
};
class Final: public SomeInterface, virtual private FinalHelper
{
. . .
};
class Error: public Final // не-не
{
. . .
};
Здесь конструктор FinalHelper должен будет быть вызван из конструктора Error (если бы наследование было невиртуальным, этот конструктор вызывался бы из конструктора Final), а Error не имеет к нему доступа, потому что он private.
Здравствуйте, McSeem2, Вы писали:
MS>Без наследования можно обойтись. И даже нужно, полностью сохраняя при этом идею полиморфизма. Но не в C++, Java, C# и тому подобных. Сама идея наследования как расширения функциональности является глубоко порочной и противоречит сущности нашего мира. Особенный LOL вызывают попытки порождения производных классов от std::string, std::vector<MyType> и тому подобных. Наследование должно быть только специализацией функциональности и ничем более. Короче, нет виртуальных функций в базовом классе? — наследование запрещено. Вот так должно быть IMSO. Но тогда это уже и не наследование получается, а некая динамическая специализация. А тот беспредел, что сейчас имеется, в конечном итоге приводит к обилию нелепых конструкций, типа ((my_string*)&std_str)->my_compare_with(b);
Полностью согласен.
Хотя есть все-таки несколько исключений из этого правила:
— Наследование вместо агрегации (не нужно лишний раз обращаться к переменной). Но в этом случае очевидно должно быть защищенное наследование.
— Наследование как наследования реализации (опять-таки должно быть защищенное наследование)
— Наследование при всяких С++ "штучках" (например при реализации стратегий или статического полиморфизма)
Не все в этом мире можно выразить с помощью нулей и единиц...
Здравствуйте, McSeem2, Вы писали:
MS> Сама идея наследования как расширения функциональности является глубоко порочной и противоречит сущности нашего мира.
В окружающем мире нет сущностей, В нем нет мебели, есть конкретные стулья, кресла. В некотором месте программы можно таскать мышкой нечто имеющее x y z и w h l и это вобщем удобно иначе программы вообще невозможно былобы писать. Креслу не обязательно менять чтото в паралелепипеде, а паралелепипеду знать что на нем можно сидеть
MS>Короче, нет виртуальных функций в базовом классе? — наследование запрещено. Вот так должно быть IMSO.
Это удобная схема в которую многое укладывается. Но к сожалению не все. У нас помимо мебели есть оружие, инвентору, точка в пространстве окуда появляются черти и т.д. и некоторые опрерации для этих предметов общие, например — подвергнуть заклинанию, произвести цикл обновления, записать, отрисовать. Но при этом сущности настолько разные, что неразумно их включать в одну иерархию. Иначе это получится некий универсальный суперпредок.
Здравствуйте, Erop, Вы писали:
E>Да? А почему? Почему я не могу, например, иметь список предметов мебели в комнате, особенно если у каждого из них прописан тип, в виде аттрибута?
Ну, "если у каждого из них прописан тип, в виде аттрибута", зачем тогда иерархии? Плоская таблица (в терминологии RDBMS) решает задачу инвентаризации. А зачем еще надо "иметь список предметов мебели в комнате", кроме как для инвентаризации?
Для моделирования размещения? Тогда тем более никаких иерархий не надо. Точнее сказать, иерархия должна быть строго одноуровневая, с виртуальным методом Draw() и ему подобными.
Короче, при решении задач, все эти "иерархии", привнесенные из физического мира являются надуманными и никакого смысла не несут. Главная задача наследования — обеспечить полиморфное поведение. Это имеет смысл. Наследование как расширение функциональности — не имеет ни малейшего смысла.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, Аноним, Вы писали:
А>>Кстати про виртуальное наследование: А>>давно интересуют примеры его использования в реальных программах.
RO>Здесь конструктор FinalHelper должен будет быть вызван из конструктора Error (если бы наследование было невиртуальным, этот конструктор вызывался бы из конструктора Final), а Error не имеет к нему доступа, потому что он private.
Какой-то искусственный пример. Одна фича языка используется для реализации другой фичи языка.
Здравствуйте, McSeem2, Вы писали:
MS>Ну, "если у каждого из них прописан тип, в виде аттрибута", зачем тогда иерархии? Плоская таблица (в терминологии RDBMS) решает задачу инвентаризации. А зачем еще надо "иметь список предметов мебели в комнате", кроме как для инвентаризации?
Мало ли зачем? Скажем тебя может заинтересовать сколько мест для рассадки гостей есть в комнате, или сколько для раскладывания на ночлег. Соответсвенно нужны разные свойства. Конечно можно сделать мегаобъект "универсальное описание предмета мебели", но тогда для болшинства предметов, большинство аттрибутов будут станными...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Evgeniy13, Вы писали:
E>- Наследование вместо агрегации (не нужно лишний раз обращаться к переменной). Но в этом случае очевидно должно быть защищенное наследование. E>- Наследование как наследования реализации (опять-таки должно быть защищенное наследование)
А почему protected, а не private?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А почему protected, а не private?
А какая разнца для юзера protected или private члены? ни к тем, ни к тем он доступа не имеет. Уровни доступа придуманны для того, чтобы запретить юзеру юзать те или иные члены.
А юзать protected вместо private в наследовании выгодней, потому что наследник будет и иметь доступ к базовым, закрытым для юзера членам, т.е. сохраняется гипкость.
Во времени выполнения нет разницы, почемуб не юзать? или я что-то не то говорю?
Здравствуйте, Ruweb, Вы писали:
R>А юзать protected вместо private в наследовании выгодней, потому что наследник будет и иметь доступ к базовым, закрытым для юзера членам, т.е. сохраняется гипкость.
А почему нет нужды защищать свои потроха от своих наследников?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Ruweb, Вы писали:
R>А юзать protected вместо private в наследовании выгодней, потому что наследник будет и иметь доступ к базовым, закрытым для юзера членам, т.е. сохраняется гипкость.
Тогда вообще всегда использовать public выгодней — гибкости больше.
Я пока знаю только одно приличное применение protected, и то оно там не используется: деструкторы std::unary_function, std::iterator и прочих невиртуальных интерфейсов.