Entry tags:
Западло
[ Предупреждение: для непрограммистов неинтересно ]
Пусть у нас есть два класса - базовый Base и отнаследованный от него Derived. В Derived есть конструктор, похожий на конструктор копии с параметром типа Base.
Допустим, в программе это используется вот так:
И оно не работает.
Тщательное расследование показало эпическое западло...
В какой-то момент я внес часть кода в функцию:
И вдруг оно начало работать! Счастливый, я все так и оставил, предполагая разобраться как-нибудь потом. Сегодня это как-нибудь наступило.
Западло состоит в том, что в строке Derived d2(d1) не всегда вызывается второй конструктор и не будут выполняться "важные манипуляции". Вместо этого будет вызван "невидимый" автоматически сгенерированный конструктор-копии, и все поля будут тупо скопированы из d1 в d2.
Это происходит в том случае, если d1 имеет тип Derived. Если Base - то все хорошо. Вот почему та функция исправляла проблему. Так тоже будет работать:
Лечится это легко:
Но ведь и вляпаться тоже легко...
Пусть у нас есть два класса - базовый Base и отнаследованный от него Derived. В Derived есть конструктор, похожий на конструктор копии с параметром типа Base.
class Base { ... }; class Derived: public Base { public: Derived() {...} Derived(const Base &b) { /* важные манипуляции */ } };
Допустим, в программе это используется вот так:
Derived d1; Derived d2(d1);
И оно не работает.
Тщательное расследование показало эпическое западло...
В какой-то момент я внес часть кода в функцию:
void foo(Base &d1) { Derived d2(d1); ... } ... Derived d1; foo(d1);
И вдруг оно начало работать! Счастливый, я все так и оставил, предполагая разобраться как-нибудь потом. Сегодня это как-нибудь наступило.
Западло состоит в том, что в строке Derived d2(d1) не всегда вызывается второй конструктор и не будут выполняться "важные манипуляции". Вместо этого будет вызван "невидимый" автоматически сгенерированный конструктор-копии, и все поля будут тупо скопированы из d1 в d2.
Это происходит в том случае, если d1 имеет тип Derived. Если Base - то все хорошо. Вот почему та функция исправляла проблему. Так тоже будет работать:
Derived d2((Base&)d1);
Лечится это легко:
class Base { ... }; class Derived: public Base { public: Derived() {...} Derived(const Base &b) { /* важные манипуляции */ } Derived(const Derived &b) { /* важные манипуляции */ } };
Но ведь и вляпаться тоже легко...
no subject
Очень полезная книжка, нагуглите.
no subject
no subject
Думаю, иногда 240 стр. не слишком высокая цена за новые знания.
no subject
no subject
no subject
no subject
Использование ссылок в inline-функции, которая в 99% случаев будет работать с простыми типами.
Еще что-то... ах да, идеологических сентенций типа "расширяемость С++ это круто, поэтому давайте все время ориентироваться на нее".
no subject
"Использование const вместо #define для числовых констант"
чуть подробнее.
А то мне предстоит программу на с++ делать, а опыта мало,
тот, что был, почти выветрился.
no subject
Для ламера надо вызубрить некое правило, как можно более простое и бездумное. Например, "препроцессор - плохо, const - хорошо". Без всяких оговорок типа, когда, где и при каких условиях. Если же подходить с практических позиций, то лучше далеко не всегда и не везде. Но это надо чуть-чуть мозги включать и вникать.
Конкретно в отношении const.
1. Для автоматических переменных получается переменная, ограниченная по области видимости. Это бонус, отмечаем его как "+1". Плата за это небольшая - чуть больше писать:
#define MAX_CHANNEL 2
и
const int MAX_CHANNEL = 2;
Поскольку писать надо больше совсем чуть-чуть, можно отметить это не как "-1", а, скажем, "-0.5". Итого: +1 против -0.5. Вывод - для автоматических переменных const немного лучше.
2. Для глобальных переменных у const пропадает бонус ограниченной области видимости. Зато может появиться другой бонус: в отладчике видно ее значение, а значение #define не видно. Но это зависит от отладчика. Иной отладчик и #define видит. Так что получается "+0.5". Далее, начинаются несовместимости между C и C++, разные тонкости с версиями компиляторов. Но это тоже редкое явление, так что тоже "-0.5". И еще "-0.5" за то, что длинее.
Итого: +0.5 против -1. Вывод - для глобальных переменных const немного хуже.
3. Если числовая константа - член класса, то для корректного оформления в виде const придется вносить правку и в хэдер, и в исходник, количество писанины растет:
.h:
static const int MAX_CHANNEL = 2;
.cpp:
const int ClassName::MAX_CHANNEL;
Это уже -1. При написании кода появляется необходимость переключаться между файлами. Еще -1. За одно и то же время можно написать константу через const, либо константу через #define плюс комментарий к ней.
Итого: +1 против -2. Вывод - для констант класса const уже намного хуже.
Но самое прикольное то, что есть enum, который лучше, чем #define и лучше, чем const в случаях 2 и 3. Он и показывается в отладчике, и позволяет ограничивать область видимости классом, и не требует залезать в .cpp, и писанины не больше:
enum { MAX_CHANNEL = 2 };
Но enum - "не идеологичен". ;)
Вывод не для ламеров: для автоматических констант юзать const, для глобальных констант (в том числе констант класса) юзать enum.
no subject
no subject
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
#define MAX_CHANNEL 2
и
const int MAX_CHANNEL = 2;
Поскольку писать надо больше совсем чуть-чуть, можно отметить это не как "-1", а, скажем, "-0.5". Итого: +1 против -0.5. Вывод - для автоматических переменных const немного лучше.
------
Писать больше только для типизации. Если она нужна (а она часто именно нужна, хотя обезьяне с гранатой она обычно не нужна; а в макросах возможности типизации(отобрать гранату) нет).
Если программист привык писать наобум, то держи достойную замену:
const MAX_CHANNEL = 2; // без int, все работает
Ограничение области видимости - это возможность. При желании const можно засунуть в namespace, define же лишены этой привилегии и могут разнести в пух и прах кучу любого подключенного кода, и хорошо если это компилятор заметит. const'ы же избавляют от множества потенциальных ошибок данного рода, за что им в данной шкале +10. Обычно это понимают только после наступленияы
------------
2. Для глобальных переменных у const пропадает бонус ограниченной области видимости.
------------
Глобальное пространство имен лучше вообще не засорять. За всю историю использования плюсов в боевых проектах мне приходилось использовать глобальные константы только в единичных случаях пару раз.
------------
3. Если числовая константа - член класса, то для корректного оформления в виде const придется вносить правку и в хэдер, и в исходник, количество писанины растет:
.h:
static const int MAX_CHANNEL = 2;
.cpp:
const int ClassName::MAX_CHANNEL;
Это уже -1. При написании кода появляется необходимость переключаться между файлами. Еще -1. За одно и то же время можно написать константу через const, либо константу через #define плюс комментарий к ней.
Итого: +1 против -2. Вывод - для констант класса const уже намного хуже.
--------------
Тут вообще глупость написана. Потому что define не может быть членом класса. Потому он не имеет никакого преимущества. Возможность прописать const в класс является дополнительной возможностью, которую можно использовать по своему усмотрению, что несомненно '+'.
--------------
В свое время мой вывод не для ламеров - везде где можно заменить константу define на const - нужно это делать, и при этом провести типизацию.
define же использовать для хитрожопых конструкций замены, экзотических случаев или случаев, когда этого требует комплиятор/библиотека или ещё кто.
no subject
недописано (;
после наступления на грабли и очухивания и обхода их в течении часов или даже дней глубокой отладки.
no subject
Вот это как раз - "достойный" пример бездумного следования религиозной заповеди: "типизация - это хорошо" - всегда, независимо ни от чего. А теперь просвети меня, как и почему в данном конкретном случае типизация - это хорошо? Не в параметрах функций, а вот конкретно для констант. Слабо обосновать? Ну и для закрепления пройденного, подумай: что, у констант типов нет? Суффиксы L, U, F не для эстетов? :)
[ Ограничение области видимости - это возможность. ]
Ты вообще читаешь то, что комментируешь? Я отметил, что "это бонус" - какие претензии, не понимаю.
[ за что им в данной шкале +10 ]
А вот это - уже религиозно-идеологическое воззрение. Для холиваров - прекрасно, для серьезного рассмотрения - негодно. Может, сразу +1000^1000? :) Ну чиста патаму шта эта крута!? :)
[ Потому что define не может быть членом класса. ]
Следи за руками:
#define ClassName__MAX_CHANNEL = 2;
:)
Ну и про enum не забудь, он все равно лучше.
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
Накося, выкуси.
Re: Накося, выкуси.
Re: Накося, выкуси.
Re: Накося, выкуси.
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
И эта... Я не хотел, чтобы Вы втянулись в спор. Извините, если что.
(no subject)
no subject
Так вот, пару слов.
Во-первых, про enum. Как правильно заметил бсивко, мейерс именно что активно рекомендует использовать enum. Он просто говорит, что в программистских кругах сложилось название для подобного использования enum-а - "enum hack". Но из текста (английского по крайней мере) совершенно никак не следует, что это нечто грязное и нечистоплотное, наоборот, этот "хак" преподносится как нечто, что следует знать и использовать.
Во-вторых, про пункт 3, то есть, про константы - члены класса. Тот же мейерс в той же главе пишет, что для типов int, char и bool объявлять переменную в .cpp не нужно - достаточно декларации в хедере, что является стандартом языка. Правда, некоторые старые компиляторы этого могут не поддерживать, но более-менее новые должны. Поэтому писанины становится меньше в два раза.
Ну и в-третьих, пустые холивары всегда бывают от абсолютизации чего-то. Того же мейерса делать непогрешимым кумиром вряд ли стоит. С другой стороны, также вряд ли стоит утверждать его ламерство, в то время как он является распространенным и уважаемым автором для многих программистских коллективов. Скажем, ты можешь не разделять их и бсивко воззрения на минимизацию времени на отладку и поиск багов, но они в свою очередь, могут не разделить твое видение себя в их рядах в случае поиска работы... :)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
no subject
no subject
итого: «а этот пацак всё время думает на языках, продолжения которых не знает!» (ц)
no subject
no subject
no subject
ты ж, вроде бы, не первый год на цпп пишешь, вообще должен «влёт» такое замечать. если уж я, который цпп люто ненавидит и пишет в нём в 90% случаев c-style код, вижу…
это, по-моему, во всех книжках напрочь говорится почти сразу: «если явного конструктора копирования нет, компилятор нашаманит свой. везде и завсегда».
зыж херня это всё. (томно вздыхает) вот шаблоооны… «ах, швецiя!» (ц)
no subject
а про Щаблоны хошь задачку прикольную? :)
no subject
no subject
http://psilogic.livejournal.com/326274.html