Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - [12]

Шрифт
Интервал

>std::vector::const_iterator citer = // citer работает как const T*

>vec.begin();

>*citer = 10; // ошибка! *citer константный

>++citer; // нормально, citer изменяется


Некоторые из наиболее интересных применений const связаны с объявлениями функций. В этом случае const может относиться к возвращаемому функцией значению, к отдельным параметрам, а для функций-членов – еще и к функции в целом.

Если указать в объявлении функции, что она возвращает константное значение, то можно уменьшить количество ошибок в клиентских программах, не снижая уровня безопасности и эффективности. Например, рассмотрим объявление функции operator* для рациональных чисел, введенное в правиле 24:


>class Rational {…}

>const Rational operator*(const Rational& lhs, const Rational& rhs);


Многие программисты удивятся, впервые увидев такое объявление. Почему результат функции operator* должен быть константным объектом? Потому что в противном случае пользователь получил бы возможность делать вещи, которые иначе как надругательством над здравым смыслом не назовешь:


>Rational a, b, c;

>…

>(a*b)=c; // присваивание произведению a*b!


Я не знаю, с какой стати программисту пришло бы в голову присваивать значение произведению двух чисел, но могу точно сказать, что иногда такое может случиться по недосмотру. Достаточно простой опечатки (при условии, что тип может быть преобразован к bool):


>if (a*b = c)... // имелось в виду сравнение!


Такой код был бы совершенно некорректным, если бы a и b имели встроенный тип. Одним из критериев качества пользовательских типов является совместимость со встроенными (см. также правило 18), а возможность присваивания значения результату произведения двух объектов представляется мне весьма далекой от совместимости. Если же объявить, что operator* возвращает константное значение, то такая ситуация станет невозможной. Вот почему Так Следует Поступать.

В отношении аргументов с модификатором const трудно сказать что-то новое; они ведут себя как локальные константные const-объекты. Всюду, где возможно, добавляйте этот модификатор. Если модифицировать аргумент или локальный объект нет необходимости, объявите его как const. Вам всего-то придется набрать шесть символов, зато это предотвратит досадные ошибки типа «хотел напечатать ==, а нечаянно напечатал =» (к чему это приводит, мы только что видели).

Константные функции-члены

Назначение модификатора const в объявлении функций-членов – определить, какие из них можно вызывать для константных объектов. Такие функции-члены важны по двум причинам. Во-первых, они облегчают понимание интерфейса класса, ведь полезно сразу видеть, какие функции могут модифицировать объект, а какие нет. Во-вторых, они обеспечивают возможность работать с константными объектами. Это очень важно для написания эффективного кода, потому что, как объясняется в правиле 20, один из основных способов повысить производительность программ на C++ – передавать объекты по ссылке на константу. Но эта техника будет работать только в случае, когда функции-члены для манипулирования константными объектами объявлены с модификатором const.

Многие упускают из виду, что функции, отличающиеся только наличием const в объявлении, могут быть перегружены. Это, однако, важное свойство C++. Рассмотрим класс, представляющий блок текста:


>class TextBlock {

>public:

>...

>const char& operator[](std::size_t position) const // operator[] для

>{return text[position];} // константных объектов

>char& operator[](std::size_t position) // operator[] для

>{return text[position];} // неконстантных объектов

>private:

>std::string text;

>};


Функцию operator[] в классе TextBlock можно использовать следующим образом:


>TextBlock tb(“Hello”);

>Std::cout << tb[0]; // вызов неконстантного

>// оператора TextBlock::operator[]

>const TextBlock ctb(“World”);

>Std::cout << ctb[0]; // вызов константного

>// оператора TextBlock::operator[]


Кстати, константные объекты чаще всего встречаются в реальных программах в результате передачи по указателю или ссылке на константу. Приведенный выше пример ctb является довольно искусственным. Но вот вам более реалистичный:


>void print(const TextBlock& ctb) // в этой функции ctb – ссылка

>// на константный объект

>{

>std::cout << ctb[0]; // вызов const TextBlock::operator[]

>...

>}


Перегружая operator[] и создавая различные версии с разными возвращаемыми типами, вы можете по-разному обрабатывать константные и неконстантные объекты TextBlock:


>std::cout << tb[0]; // нормально – читается

>// неконстантный TextBlock

>tb[0] = ‘x’; // нормально – пишется

>// неконстантный TextBlock

>std::cout << ctb[0]; // нормально – читается

>// константный TextBlock

>ctb[0] = ‘x’; // ошибка! – запись

>// константного TextBlock


Отметим, что ошибка здесь связана только с типом значения, возвращаемого operator[]; сам вызов operator[] проходит нормально. Причина ошибки – в попытке присвоить значение объекту типа const char&, потому что это именно такой тип возвращается константной версией operator[].

Отметим также, что тип, возвращаемый неконстантной версией operator[], – это ссылка на char, а не сам char. Если бы operator[] возвращал просто char, то следующее предложение не скомпилировалось бы:


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Создание инструмента научных исследований на основе XML: Проблемы и методология

"В своем докладе я опишу процесс создания электронного исследовательского инструмента, имеющего в своей основе печатный библиографический указатель, который предназначен для использования в научных целях, а также проанализирую некоторые трудности, с которыми мы столкнулись в ходе реализации данного проекта, и расскажу об избранных нами вариантах решения возникших проблем.".


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет собой уникальное учебное и справочное пособие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий Delphi».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Сущность технологии СОМ. Библиотека программиста

В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.