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
, или, другими словами, используя их, вы можете сослаться на какую-нибудь другую строку, изменяя значение указателя, но не значение, на которое он ссылается. Ничто не может помешать вам, например, сделать следующее.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.