Стенли Липпман - Язык программирования C++. Пятое издание
- Название:Язык программирования C++. Пятое издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2014
- Город:Москва
- ISBN:978-5-8459-1839-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стенли Липпман - Язык программирования C++. Пятое издание краткое содержание
Вы держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под
. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. В соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.
С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать их наилучшие способы применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.
Стенли Б. Липпман Жози Лажойе Барбара Э. Му • Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием
• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования
• Изучите принципы и узнайте почему язык С++11 работает именно так
• Воспользуйтесь множеством перекрестных ссылок, способных помочь вам объединить взаимосвязанные концепции и проникнуть в суть
• Ознакомьтесь с современными методиками обучения и извлеките пользу из упражнений, в которых подчеркиваются ключевые моменты, позволяющие избежать проблем
• Освойте лучшие методики программирования и закрепите на практике изученный материал
Исходный код примеров можно загрузить с веб-страницы книги на сайте издательства по адресу: http://www.williamspublishing.com
Язык программирования C++. Пятое издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
j = i++; // j = 1, i = 2: постфикс возвращает исходное значение
Операндами этих операторов должны быть l-значения. Префиксные операторы возвращают сам объект как l-значение. Постфиксные операторы возвращают копию исходного значения объекта как r-значение.
Читатели с опытом языка С могли бы быть удивлены тем, что в написанных до сих пор программах использовался префиксный оператор инкремента. Причина проста: префиксная версия позволяет избежать ненужной работы. Она увеличивает значение и возвращает результат. Постфиксный оператор должен хранить исходное значение, чтобы возвратить неувеличенное значение как результат. Но если в исходном значении нет никакой потребности, то нет необходимости и в дополнительных действиях, осуществляемых постфиксным оператором.
Для переменных типа int
и указателей компилятор способен оптимизировать код и уменьшить количество дополнительных действий. Для более сложных типов итераторов подобные дополнительные действия могут обойтись довольно дорого. При использовании префиксных версий об эффективности можно не волноваться. Кроме того, а возможно и важнее всего то, что так можно выразить свои намерения более непосредственно.

Постфиксные версии операторов ++
и --
используются в случае, когда в одном составном выражении необходимо использовать текущее значение переменной, а затем увеличить его.
В качестве примера используем постфиксный оператор инкремента для написания цикла, выводящего значения вектора до, но не включая, первого отрицательного значения.
auto pbeg = v.begin();
// отображать элементы до первого отрицательного значения
while (pbeg != v.end() && *beg >= 0)
cout << *pbeg++ << endl; // отобразить текущее значение и
// переместить указатель pbeg
Выражение *pbeg++
обычно малопонятно новичкам в языках С++ и С. Но поскольку эта схема весьма распространена, программисты С++ должны понимать такие выражения.
Приоритет постфиксного оператора инкремента выше, чем оператора обращения к значению, поэтому код *pbeg++
эквивалентен коду *(pbeg++)
. Часть pbeg++
осуществляет инкремент указателя pbeg
и возвращает как результат копию предыдущего значения указателя pbeg
. Таким образом, операндом оператора *
будет неувеличенное значение указателя pbeg
. Следовательно, оператор выводит элемент, на который первоначально указывал указатель pbeg
, а затем осуществляет его инкремент.
Этот подход основан на том, что постфиксный оператор инкремента возвращает копию своего исходного, не увеличенного операнда. Если бы он возвратил увеличенное значение, то обращение к элементу вектора по такому увеличенному значению привело бы к плачевным результатам: первым оказался бы незаписанный элемент вектора. Хуже того, если бы у последовательности не было никаких отрицательных значений, то в конце произошла бы попытка обращения к значению несуществующего элемента за концом вектора.
Такие выражения, как *iter++
, могут быть не очевидны, однако они весьма популярны. Следующая форма записи проще и менее подвержена ошибкам:
cout << *iter++ << endl;
чем ее более подробный эквивалент:
cout << *iter << endl;
++iter;
Поэтому примеры подобного кода имеет смысл внимательно изучать, чтобы они стали совершенно понятны. В большинстве программ С++ используются краткие формы выражений, а не их более подробные эквиваленты. Поэтому программистам С++ придется привыкать к ним. Кроме того, научившись работать с краткими формами, можно заметить, что они существенно менее подвержены ошибкам.
Большинство операторов не гарантирует последовательности обработки операндов (см. раздел 4.1.3). Отсутствие гарантированного порядка зачастую не имеет значения. Это действительно имеет значение в случае, когда выражение одного операнда изменяет значение, используемое выражением другого. Поскольку операторы инкремента и декремента изменяют свои операнды, очень просто неправильно использовать эти операторы в составных выражениях.
Для иллюстрации проблемы перепишем цикл из раздела 3.4.1, который преобразует в верхний регистр символы первого введенного слова:
for (auto it = s.begin(); it != s.end() && !isspace(*it) ; ++it)
it = toupper(*it); // преобразовать в верхний регистр
Этот пример использует цикл for
, позволяющий отделить оператор обращения к значению beg
от оператора его приращения. Замена цикла for
, казалось бы, эквивалентным циклом while
дает неопределенные результаты:
// поведение следующего цикла неопределенно!
while (beg != s.end() && !isspace(*beg))
beg = toupper(*beg++); // ошибка: это присвоение неопределенно
Проблема пересмотренной версии в том, что левый и правый операнды оператора =
используют значение, на которое указывает beg
, и правый его изменяет. Поэтому присвоение неопределенно. Компилятор мог бы обработать это выражение так:
*beg = toupper(*beg); // сначала обрабатывается левая сторона
*(beg + 1) = toupper(*beg); // сначала обрабатывается правая сторона
Или любым другим способом.
Упражнение 4.17. Объясните различие между префиксным и постфиксным инкрементом.
Упражнение 4.18. Что будет, если цикл while
из последнего пункта этого раздела, используемый для отображения элементов вектора, задействует префиксный оператор инкремента?
Упражнение 4.19. С учетом того, что ptr
указывает на тип int
, vec
— вектор vector
, a ival
имеет тип int
, объясните поведение каждого из следующих выражений. Есть ли среди них неправильные? Почему? Как их исправить?
(a) ptr != 0 && *ptr++ (b) ival++ && ival
(с) vec[ival++] <= vec[ival]
4.6. Операторы доступа к членам
Операторы точка ( .
) (dot operator) (см. раздел 1.5.2) и стрелка ( ->
) (arrow operator) (см. раздел 3.4.1) обеспечивают доступ к члену. Оператор точка выбирает член из объекта типа класса; оператор стрелка определен так, что код ptr -> mem
эквивалентен коду (* ptr ). mem
.
string s1 = "a string", *p = &s1;
auto n = s1.size(); // вызов функции-члена size() строки s1
n = (*p).size(); // вызов функции-члена size() объекта, на который
Интервал:
Закладка: