В первом случае – мы будем использовать только одну из копий объекта 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 и прочих невиртуальных интерфейсов.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Evgeniy13, Вы писали:
E>>- Наследование вместо агрегации (не нужно лишний раз обращаться к переменной). Но в этом случае очевидно должно быть защищенное наследование. E>>- Наследование как наследования реализации (опять-таки должно быть защищенное наследование)
E>А почему protected, а не private?
Не я имел в виду на самом деле любое наследование кроме открытого. Что конкретно (protected или private) зависит от конкретного дизайна.
Не все в этом мире можно выразить с помощью нулей и единиц...
Здравствуйте, Roman Odaisky, Вы писали:
RO>Есть вот такой баян, запрещающий наследование от определенного класса: RO>
RO>class Final;
RO>class FinalHelper
RO>{
RO>friend class Final;
RO>private:
RO> FinalHelper() { }
RO>};
RO>class Final: public SomeInterface, virtual private FinalHelper
RO>{
RO> . . .
RO>};
RO>class Error: public Final // не-не
RO>{
RO> . . .
RO>};
RO>
RO>Здесь конструктор FinalHelper должен будет быть вызван из конструктора Error (если бы наследование было невиртуальным, этот конструктор вызывался бы из конструктора Final), а Error не имеет к нему доступа, потому что он private.
Крайне сомнительно что FinalHelper позовется. Во всяком случае онлайн компиляторы http://www.comeaucomputing.com/tryitout/ и http://www.interstron.ru/eng/text.asp?id=3792 сожрали это без вопросов
Ну типа FinalHelper не будет конструироваться, что ли?
Попробуй создать объект выведенного класса...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Попробуй создать объект выведенного класса...
Попробовал — действительно не создаются обьекты. Но FinalHelper в Error нужен ли? В принципе его могли позвать и из Final.
Чтоб скомпилировать создание обьекта Error нужно и friend class Error; и friend class Final; . Но ведь зовется то только один конструктор
Здравствуйте, Programador, Вы писали:
P>Чтоб скомпилировать создание обьекта Error нужно и friend class Error; и friend class Final; . Но ведь зовется то только один конструктор
Конструктор виртуальной базы зовётся из самого выведенного объекта. Если не понятно почему это так, то могу объяснить (глупый ответ "по стандарту" )
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Конструктор виртуальной базы зовётся из самого выведенного объекта. Если не понятно почему это так, то могу объяснить (глупый ответ "по стандарту" )
Оба friend нужны. Но в одном из классов конструктор не нужен. Вопрос или в стандарте сказано проверить сначала на даступность, а потом на нужность? Или они тексты друг у друга воруют
class Final;
class FinalHelper
{
friend class Error;
friend class Final;private:
FinalHelper() { }
};
class Final: virtual private FinalHelper
{
};
class Error: public Final // не-не
{
};
Error ee;
Здравствуйте, Erop, Вы писали:
E>Мало ли зачем? Скажем тебя может заинтересовать сколько мест для рассадки гостей есть в комнате, или сколько для раскладывания на ночлег. Соответсвенно нужны разные свойства.
Таким образом, ты ведешь речь о сферической лошади в вакууме, никому на практике не нужной.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
MS>Таким образом, ты ведешь речь о сферической лошади в вакууме, никому на практике не нужной.
Таким образом я не хочу описывать реальную сложную задачу, где ООП иерархии имеют смысл. Конечно в мегапродукте "Hellow World" без наследования обычно можно легко обойтись
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Programador, Вы писали:
P>Оба friend нужны. Но в одном из классов конструктор не нужен. Вопрос или в стандарте сказано проверить сначала на даступность, а потом на нужность? Или они тексты друг у друга воруют
Как-то не понятно что бы обозначало выделенное
По стандарту непосредственно из конструктора самого выведенного класса зовутся конструкторы всех виртуальных баз. Соответсвенно их нужно позвать и для этого нужен доступ.
Или ты имеешь в виду, что конструктор FinalHelper ничего не делает?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Как-то не понятно что бы обозначало выделенное E>По стандарту непосредственно из конструктора самого выведенного класса зовутся конструкторы всех виртуальных баз. Соответсвенно их нужно позвать и для этого нужен доступ.
Но тогда он не зовется из Final , а без friend class Final; не компилируется.
Здравствуйте, McSeem2, Вы писали:
E>>Мало ли зачем? Скажем тебя может заинтересовать сколько мест для рассадки гостей есть в комнате, или сколько для раскладывания на ночлег. Соответсвенно нужны разные свойства.
MS>Таким образом, ты ведешь речь о сферической лошади в вакууме, никому на практике не нужной.
так это в идеальной задаче нужно чтото одно, а в реальной сегодня одно, завтра другое и то что позавчера не перестает быть нужно
Здравствуйте, Programador, Вы писали:
P>Но тогда он не зовется из Final , а без friend class Final; не компилируется.
Ну он должен таки иметь возможность позваться.
Груба говоря, все виртуальные наследники, даже и непрямые, должны действовть так: "Если виртуальная база ещё не создана -- создать"
Ты же не знаешь из какого контекста это всё позовут.
Вот ты запихнёшь это всё в библиотеку, скомпилишь и отдашь, а пользователи захотят и позовут copy-constructor Final от Error...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Груба говоря, все виртуальные наследники, даже и непрямые, должны действовть так: "Если виртуальная база ещё не создана -- создать"
Тоесть "не создана" определяется в рунтайм? — но это уже вопрос скорее топикстартеру
Здравствуйте, Programador, Вы писали:
MS>>Таким образом, ты ведешь речь о сферической лошади в вакууме, никому на практике не нужной. P>так это в идеальной задаче нужно чтото одно, а в реальной сегодня одно, завтра другое и то что позавчера не перестает быть нужно
Ну вот и ответ на вопрос. Надо обеспечить нормальную полиморфность с виртуальными функциями. А если их нет, то зачем тогда наследование?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[8]: protected vs private
От:
Аноним
Дата:
10.09.07 14:56
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:
RO>Я пока знаю только одно приличное применение protected, и то оно там не используется: деструкторы std::unary_function, std::iterator и прочих невиртуальных интерфейсов.
я тебе еще одно подскажу. Есть класс для работы с http протоколом и класс для работы с http протоколом, который наследует первый класс. Медод int sk нужен и тому и другому классу, делаем его protected.
Можно делать всё публик, но тогда зачем юзать классы?, юзать структуры!, строчку public писать не нужно будет, и на одну строку будет кода меньше — но это выглядит не профессионально. У меня привычка закрывать от юзера данные, которые ему не нужно знать, а то он в еще в целях экономии памяти запишит, что — нибуть туда, ну или мало ли.
Читать профессиональный код намного приятней.
А protected'ить от самого себя данные — не вижу смысла, я то знаю какой метод для чего предназначен.
И еще мне одна идея пришла в голову, почему не нужно открывать все члены. Наверно есть ide или будут, которые не будут выдавать в списке членов, члены, которые закрыты, когда программист будет вводить оператор расширения области видимости.
Re[9]: protected vs private
От:
Аноним
Дата:
10.09.07 15:14
Оценка:
McSeem2 метод, который заменяется в наследнике, не всегда выгодно делать виртуальной, например когда ты вызываешь метод не через указательна на базовый класс, а через указательно на этот класс
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, Аноним, Вы писали:
А>>Кстати про виртуальное наследование: А>>давно интересуют примеры его использования в реальных программах.
RO>Есть вот такой баян, запрещающий наследование от определенного класса: RO>
RO>class Final;
RO>class FinalHelper
RO>{
RO>friend class Final;
RO>private:
RO> FinalHelper() { }
RO>};
RO>class Final: public SomeInterface, virtual private FinalHelper
RO>{
RO> . . .
RO>};
RO>class Error: public Final // не-не
RO>{
RO> . . .
RO>};
RO>
RO>Здесь конструктор FinalHelper должен будет быть вызван из конструктора Error (если бы наследование было невиртуальным, этот конструктор вызывался бы из конструктора Final), а Error не имеет к нему доступа, потому что он private.
Кстати где-то читал, что данную конструкцию нельзя создать на шаблонах, т.к. конструкция
template<typename T> class a{ friend class T;}
не соответствует стандарту. Вот пример который вроде не противоречит стандарту:
template<typename T>
struct type2type{ typedef T type; };
template<typename T>
class final;
template<typename T>
class final_helper
{
friend class type2type< final<T> >::type;
friend class type2type< T >::type;
private:
final_helper(){};
};
template<typename T>
class final: virtual public final_helper< T >{};
class a: final<a>{};
class b: public a{};
void main()
{
a aa;
b bb; // error: К сожалению ошибку выдаст только при попытке создать объект, но все же лучше чем ничего
}
Здравствуйте, Programador, Вы писали:
P>Тоесть "не создана" определяется в рунтайм? — но это уже вопрос скорее топикстартеру
Нет, такое поведение стандартом, конечно, не навязывается. Напрмиер, может быть скрытый аргумент конструктора, или дополнительная точка входа в конструктор (для конструирования наиболее выведенного объекта и для конструирования базы)
Но в любом случае Каждый из конструкторов может быть вызван из более поздно написанного кода из другой единицы трансляции...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали:
А>А protected'ить от самого себя данные — не вижу смысла, я то знаю какой метод для чего предназначен.
Через месяц/год ты уже понятия не будешь иметь, какой метод для чего нужен.
Не говоря уже о другом человеке, который, возможно, будет поддерживать твой код.
А кодирование в стиле "все паблик" применимо только к проектам типа "сдал и забыл" (курсовая, например).
You will always get what you always got
If you always do what you always did
Re[4]: Виртуальное наследование
От:
Аноним
Дата:
12.09.07 16:26
Оценка:
Здравствуйте, s_viy, Вы писали:
>Кстати где-то читал, что данную конструкцию нельзя создать на шаблонах, т.к. конструкция
template<typename T> class a{ friend class T;}
не соответствует стандарту. Вот пример который вроде не противоречит стандарту:
>template<typename T>
>struct type2type{ typedef T type; };
>template<typename T>
>class final;
>template<typename T>
>class final_helper
>{
> friend class type2type< final<T> >::type;
> friend class type2type< T >::type;
>private:
> final_helper(){};
>};
>template<typename T>
>class final: virtual public final_helper< T >{};
>class a: final<a>{};
>class b: public a{};
>void main()
>{
> a aa;
> b bb; // error: К сожалению ошибку выдаст только при попытке создать объект, но все же лучше чем ничего
>}
>