C++. Сборник рецептов - [203]

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

В отличие от данного члена с функцией-членом вы не можете сделать то же самое, потому что это бессмысленно. Рассмотрим указатель на функцию, имеющую такую же сигнатуру, как >MyClass::incr (т.е. он возвращает >void и не имеет аргументов).

>void (*pf)();

Теперь попытайтесь присвоить этому указателю адрес функции-члена.

>pf = &MyClass::incr; // He получится

>pf = &obj.incr;      // И это не пройдет

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

См. также

Рецепт 15.1.

15.3. Обеспечение невозможности модификации аргумента в функции

Проблема

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

Решение

Для предотвращения изменения аргументов вашей функцией объявите ее аргументы с ключевым словом >const. Короткий пример 15.3 показывает, как это можно сделать.

Пример 15.3. Гарантия невозможности модификации аргументов

>#include

>#include


>void concat(const std::string& s1, // Аргументы объявлены как константное,

> const std::string& s2,            // поэтому не могут быть изменены

> std::string& out) {

> out = s1 + s2;

>}


>int main() {

> std::string s1 = "Cabo ";

> std::string s2 = "Wabo";

> std::string s3;

> concat(s1, s2, s3);

> std::cout << "s1 = " << s1 << '\n';

> std::cout << "s2 = " << s2 << '\n';

> std::cout << "s3 = " << s3 << '\n';

>}

Обсуждение

В примере 15.3 продемонстрировано прямое использование ключевого слова >const. Существует две причины объявления параметров вашей функции с этим ключевым словом, когда вы не планируете их изменять. Во-первых, этим вы сообщаете о своих намерениях читателям вашего программного кода. Объявляя параметр как >const, вы фактически говорите, что он является входным параметром. Это позволяет пользователям вашей функции писать программный код в расчете на то, что эти значения не будут изменены. Во-вторых, это позволяет компилятору запретить любые модифицирующие операции на тот случай, если вы случайно их используете. Рассмотрим небезопасную версию >concat из примера 15 3.

>void concatUnsafe(std::string& s1,

> std::string& s2 std::string& out) {

> out = s1 += s2; // Ну вот, записано значение в s1

>}

Несмотря на мою привычку тщательно подходить к кодированию программ, я сделал глупую ошибку и написал >+= вместо >+. В результате при вызове >concatUnsafe будут модифицированы аргументы >out и >s1, что может оказаться сюрпризом для пользователя, который едва ли рассчитывает на модификацию одной из исходных строк.

Спасти может >const. Создайте новую функцию >concatSafe, объявите переменные константными, как показано в примере 15.3, и функция не будет откомпилирована.

>void concatSafe(const std::string& s1,

> const std::string& s2, std::string& out) {

> out = s1 += s2; // Теперь вы получите ошибку компиляции

>}

>concatSafе гарантирует неизменяемость значений в >s1 и >s2. Эта функция делает еще кое-что: она позволяет пользователю передавать константные аргументы. Например, программный код, выполняющий конкатенацию строк, мог бы выглядеть следующим образом.

>void myFunc(const std::string& s) { // Обратите внимание, что s является

>                                    // константной переменной

> std::string dest;

> std::string tmp = "foo";

> concatUnsafe(s, tmp, dest); // Ошибка: s - константная переменная

>                             // Выполнить какие-то действия с dest...

>}

В данном случае функция >myFunc не будет откомпилирована, потому что >concatUnsafe не обеспечивает >const'антность >myFunc. >myFunc гарантирует внешнему миру, что она не будет модифицировать содержимое >s, т.е. все действия с >s внутри тела >myFunc не должны нарушать это обещание. Конечно, вы можете обойти это ограничение, используя оператор >const_cast и тем самым освобождаясь от константности, но такой подход ненадежен, и его следует избегать. В этой ситуации >concatSafe будет компилироваться и выполняться нормально.

Указатели вносят темные штрихи в розовую картину >const. Когда вы объявляете переменную-указатель как параметр, вы имеет дело с двумя объектами: самим адресом и то, на что ссылается этот адрес. C++ позволяет использовать >const для ограничения действий по отношению к обоим объектам. Рассмотрим еще одну функцию конкатенации, которая использует указатели.

>void concatUnsafePtr(std::string* ps1,

> std::string* ps2, std::string* pout) {

> *pout = *ps1 + *ps2;

>}

Здесь такая же проблема, как в примере с >concatUnsafe, описанном ранее. Добавьте >const для гарантии невозможности обновления исходных строк.

>void concatSaferPtr(const std::string* ps1,

> const std::string* ps2, std::string* pout) {

> *pout = *ps1 + *ps2;

>}

Отлично, теперь вы не можете изменить >*ps1 и >*ps2. Но вы по-прежнему можете изменить >ps1 и >ps2, или, другими словами, используя их, вы можете сослаться на какую-нибудь другую строку, изменяя значение указателя, но не значение, на которое он ссылается. Ничто не может помешать вам, например, сделать следующее.


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

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


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».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.