C++. Сборник рецептов - [204]
>void concatSaferPtr(const std:string* ps1,
> const std::string* ps2, std::string* pout) {
> ps1 = pout; // Ух!
> *pout = *ps1 + *ps2;
>}
Предотвратить подобные ошибки можно с помощью еще одного >const
.
>void concatSafestPtr(const std::string* const ps1,
> const std::string* const ps2, std::string* pout) {
> *pout = *ps1 + *ps2;
>}
Применение >const
по обе стороны звездочки делает вашу функцию максимально надежной. В этом случае вы ясно показываете свои намерения пользователям вашей функции, и ваша репутация не пострадает в случае описки.
Рецепт 15.4.
15.4. Обеспечение невозможности модификации своих объектов в функции-члене
Требуется вызывать функции -члены для константного объекта, но ваш компилятор жалуется на то, что он не может преобразовать тип используемого вами объекта из константного в неконстантный.
Поместите ключевое слово >const
справа от имени функции-члена при ее объявлении в классе и при ее определении. Пример 15.4 показывает, как это можно сделать
Пример 15.4. Объявление функции-члена константной
>#include
>#include
>class RecordSet {
>public:
> bool getFieldVal(int i, std::string& s) const;
> // ...
>};
>bool RecordSet::getFieldVal(int i, std::string& s) const {
> // Здесь нельзя модифицировать никакие неизменяемые
> // данные-члены (см. обсуждение)
>}
>void displayRecords(const RecordSet& rs) {
> // Здесь вы можете вызывать только константные функции-члены
> // для rs
>}
Добавление концевого >const
в объявление члена и в его определение заставляет компилятор более внимательно отнестись к тому, что делается с объектом внутри тела члена. Константным функциям-членам не разрешается выполнять неконстантные операции с данными-членами. Если такие операции присутствуют, компиляция завершится неудачно. Например, если бы в >RecordSet::getFieldVal
я обновил счетчик-член, эта функция не была бы откомпилирована (в предположении, что >getFieldCount_
является переменной-членом класса >RecordSet
).
>bool RecordSet::getFieldVal(int i, std::string& s) const {
> ++getFieldCount_; // Ошибка: константная функция-член не может
> // модифицировать переменную-член
> // ...
>}
Это может также помочь обнаружить более тонкие ошибки, подобно тому, что делает >const
в роли квалификатора переменной (см. рецепт 15.3). Рассмотрим следующую глупую ошибку.
>bool RecordSet::getFieldVal(int i, std::string& s) const {
> fieldArray_[i] = s; // Ой, я не это имел в виду
> // ...
>}
Снова компилятор преждевременно завершит работу и выдаст сообщение об ошибке, потому что вы пытаетесь изменить переменную-член, а это не разрешается делать в константных функциях-членах. Ну, при одном исключении.
В классе >RecordSet
(в таком, как (схематичный) класс в примере 15.4) вам, вероятно, потребовалось бы перемещаться туда-сюда по набору записей, используя понятие «текущей» записи. Простой способ заключается в применении переменной-члена целого типа, содержащей номер текущей записи; ваши функции-члены, предназначенные для перемещения текущей записи вперед-назад, должны увеличивать или уменьшать это значение.
>void RecordSet::gotoNextPecord() const {
> if (curIndex_ >= 0 && curIndex_ < numRecords_-1)
> ++curIndex_;
>}
>void RecordSet::gotoPrevRecord() const {
> if (curIndex_ > 0)
> --curIndex_;
>}
Очевидно, что это не сработает, если эти функции-члены являются константными. Обе обновляют данное-член. Однако без этого пользователи класса >RecordSet
не смогут перемещаться по объекту >const RecordSet
. Это исключение из правил работы с константными функциями-членами является вполне разумным, поэтому C++ имеет механизм его поддержки: ключевое слово >mutable
.
Для того чтобы >curIndex_
можно было обновлять в константной функции-члене, объявите ее с ключевым словом mutable в объявлении класса.
>mutable int curIndex_;
Это позволит вам модифицировать >curIndex_
в любом месте. Однако этой возможностью следует пользоваться разумно, поскольку это действует на вашу функцию так, как будто она становится с этого момента неконстантной.
Применение ключевого слова >const
в примере 15.4 позволяет гарантировать невозможность изменения состояния объекта в функции-члене. В целом, такой подход дает хорошие результаты, потому что сообщает пользователям класса о режиме работы функции-члена и потому что сохраняет вам репутацию, заставляя компилятор проконтролировать отсутствие в функции-члене непредусмотренных действий.
15.5. Написание оператора, не являющегося функцией-членом
Необходимо написать бинарный оператор, и вы не можете или не хотите сделать его функцией-членом класса.
Используйте ключевое слово >operator
, временную переменную и конструктор копирования для выполнения основной работы и возвратите временный объект. В примере 15.5 приводится простой оператор конкатенации строк для пользовательского класса >String
.
Пример 15.5. Конкатенация с использованием оператора не члена
>#include
>#include
>class String { // Предположим, что объявление класса String содержит,
> // по крайней мере, все, что указанно ниже
>public:
> String();
> String(const char* p);
> String(const String& orig);
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.