- •0. Введение: о курсе: версия для печати и pda
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.5 Объектно-ориентированное программирование
- •1.5.1 Механизм вызова
- •1.5.3 Множественное наследование
- •1.6 Пределы совершенства
- •2. Лекция: Описания и константы: версия для печати и pda
- •2.2 Имена
- •2.3.2 Неявное преобразование типа
- •2.4 Литералы
- •2.4.4 Строки
- •2.6. Экономия памяти
- •2.6.1 Поля
- •3.1.1 Анализатор
- •3.1.2 Функция ввода
- •3.2 Сводка операций
- •3.2.3 Инкремент и декремент
- •3.2.5 Преобразование типа
- •3.2.6 Свободная память
- •3.3.2 Оператор goto
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •5.5.3 Свободная память
- •5.5.5 Массивы объектов класса
- •6. Лекция: Производные классы: версия для печати и pda
- •6.1 Введение и краткий обзор
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.4.1 Монитор экрана
- •6.5 Множественное наследование
- •7.3 Пользовательские операции преобразования типа
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.5 Большие объекты
- •Int size; // размер вектора, на который указывает p
- •7.13 Предостережения
- •7.14 Упражнения
- •8. Лекция: Шаблоны типа: версия для печати и pda
- •8.1 Введение
- •8.3.2 Список без принудительной связи
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.7.1 Задание реализации с помощью параметров шаблона
- •9.1.2 Другие точки зрения на особые ситуации
- •9.3.2 Производные особые ситуации
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.9 Упражнения
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.4.1.2 Поля вывода
- •10.4.1.4 Вывод целых
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •X Целый параметр выдается в шестнадцатеричной записи;
- •11. Лекция: Проектирование и развитие: версия для печати и pda
- •11.1 Введение
- •11.2 Цели и средства
- •11.3 Процесс развития
- •11.3.1 Цикл развития
- •11.3.2 Цели проектирования
- •11.3.3 Шаги проектирования
- •11.3.3.1 Шаг 1: определение классов
- •11.3.3.2 Шаг 2: определение набора операций
- •11.3.3.3 Шаг 3: указание зависимостей
- •11.3.3.4 Шаг 4: определение интерфейсов
- •11.3.3.5 Перестройка иерархии классов
- •11.3.3.6 Использование моделей
- •11.3.4 Эксперимент и анализ
- •11.3.5 Тестирование
- •11.3.6 Сопровождение
- •11.3.7 Эффективность
- •11.4 Управление проектом
- •11.4.1 Повторное использование
- •11.4.2 Размер
- •11.4.3 Человеческий фактор
- •11.5 Свод правил
- •11.6 Список литературы с комментариями
- •12.1.1 Игнорирование классов
- •12.1.2 Игнорирование наследования
- •12.1.3 Игнорирование статического контроля типов
- •12.1.4 Гибридный проект
- •12.2 Классы
- •12.2.1 Что представляют классы?
- •12.2.2 Иерархии классов
- •12.2.3 Зависимости в рамках иерархии классов.
- •12.2.7 Отношения внутри класса
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •13. Лекция: Проектирование библиотек: версия для печати и pda
- •13.1 Введение
- •13.2 Конкретные типы
- •13.5.1 Информация о типе
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.10 Управление памятью
3.2 Сводка операций
Здесь приводится краткая сводка операций и несколько примеров. Каждая операция сопровождается одним или несколькими характерными для нее именами и примером ее использования. В этих примерах class_name обозначает имя класса, member - имя члена, object - выражение, задающее объект класса, pointer - выражение, задающее указатель, expr - просто выражение, а lvalue (адрес) - выражение, обозначающее не являющийся константой объект. Обозначение (type) задает имя типа в общем виде (с возможным добавлением *, () и т.д.). Если оно указано без скобок, существуют ограничения.
Порядок применения унарных операций и операций присваивания "справа налево", а всех остальных операций - "слева направо". То есть, a=b=c означает a=(b=c), a+b+c означает (a+b)+c, и *p++ означает *(p++), а не (*p)++.
____________________________________________________________
Операции С++
============================================================
:: Разрешение области видимости class_name :: member
:: Глобальное :: name
____________________________________________________________
.Выбор члена object . member
-> Выбор членаpointer -> member
[] Индексированиеpointer [ expr ]
() Вызов функции expr ( expr_list )
() Структурное значениеtype ( expr_list )
sizeof Размер объектаsizeof expr
sizeof Размер типа sizeof ( type )
____________________________________________________________
++ Постфиксный инкремент lvalue ++
++ Префиксный инкремент++ lvalue
-- Постфиксный декремент lvalue --
-- Префиксный декремент-- lvalue
~Дополнение ~ expr
!Логическое НЕ ! expr
-Унарный минус - expr
+Унарный плюс+ expr
&Взятие адреса & lvalue
*Косвенность * expr
newСоздание (размещение) new type
delete Уничтожение (освобождение) delete pointer
delete[] Уничтожение массива delete[] pointer
() Приведение(преобразование)типа ( type ) expr
____________________________________________________________
. *Выбор члена косвенный object . pointer-to-member
->*Выбор члена косвенный pointer -> pointer-to-member
____________________________________________________________
*Умножениеexpr * expr
/Деление expr / expr
%Остаток от деления expr % expr
____________________________________________________________
+Сложение (плюс) expr + expr
-Вычитание (минус) expr - expr
____________________________________________________________
Все операции таблицы, находящиеся между двумя ближайшими друг к другу горизонтальными чертами, имеют одинаковый приоритет. Приоритет операций уменьшается при движении "сверху вниз". Например, a+b*c означает a+(b*c), так как * имеет приоритет выше, чем +; а выражение a+b-c означает (a+b)-c, поскольку + и - имеют одинаковый приоритет, и операции + и - применяются "слева направо".
____________________________________________________________
Операции С++ (продолжение)
============================================================
<< Сдвиг влево expr << expr
>> Сдвиг вправо expr >> expr
____________________________________________________________
<Меньше expr < expr
<= Меньше или равно expr <= expr
>Больше expr > expr
>= Больше или равно expr >= expr
____________________________________________________________
== Равно expr == expr
!= Не равно expr != expr
____________________________________________________________
&Поразрядное Иexpr & expr
____________________________________________________________
^Поразрядное исключающее ИЛИ expr ^ expr
____________________________________________________________
|Поразрядное включающее ИЛИexpr | expr
____________________________________________________________
&& Логическое И expr && expr
____________________________________________________________
|| Логическое ИЛИ expr || expr
____________________________________________________________
? :Операция условия expr? expr : expr
____________________________________________________________
=Простое присваивание lvalue = expr
*= Присваивание с умножением lvalue *= expr
/= Присваивание с делением lvalue /= expr
%= Присваивание с взятием lvalue %= expr
остатка от деления
+= Присваивание со сложением lvalue += expr
-= Присваивание с вычитанием lvalue -= expr
<<=Присваивание со сдвигом влево lvalue <<= expr
>>=Присваивание со сдвигом вправо lvalue >>= expr
&= Присваивание с поразрядным И lvalue &= expr
|= Присваивание с поразряднымlvalue |= expr
включающим ИЛИ
^= Присваивание с поразряднымlvalue ^= expr
исключающим ИЛИ
____________________________________________________________
Запятая (последовательность) expr , expr
____________________________________________________________
3.2.1 Скобки
Синтаксис языка С++ перегружен скобками, и разнообразие их применений способно сбить с толку. Они выделяют фактические параметры при вызове функций, имена типов, задающих функции, а также служат для разрешения конфликтов между операциями с одинаковым приоритетом. К счастью, последнее встречается не слишком часто, поскольку приоритеты и порядок применения операций определены так, чтобы выражения вычислялись "естественным образом" (т.е. наиболее распространенным образом). Например, выражение
if (i<=0 || max<i) // ...
означает следующее: "Если i меньше или равно нулю, или если max меньше i". То есть, оно эквивалентно
if ( (i<=0) || (max<i) ) // ...
но не эквивалентно допустимому, хотя и бессмысленному выражению
if (i <= (0||max) < i) // ...
Тем не менее, если программист не уверен в указанных правилах, следует использовать скобки, причем некоторые предпочитают для надежности писать более длинные и менее элегантные выражения, как:
if ( (i<=0) || (max<i) ) // ...
При усложнении подвыражений скобки используются чаще. Не надо, однако, забывать, что сложные выражения являются источником ошибок. Поэтому, если у вас появится ощущение, что в этом выражении нужны скобки, лучше разбейте его на части и введите дополнительную переменную. Бывают случаи, когда приоритеты операций не приводят к "естественному" порядку вычислений. Например, в выражении
if (i&mask == 0) // ловушка! & применяется после ==
не происходит маскирование i (i&mask), а затем проверка результата на 0. Поскольку у == приоритет выше, чем у &, это выражение эквивалентно i&(mask==0). В этом случае скобки играют важную роль:
if ((i&mask) == 0) // ...
Имеет смысл привести еще одно выражение, которое вычисляется совсем не так, как мог бы ожидать неискушенный пользователь:
if (0 <= a <= 99) // ...
Оно допустимо, но интерпретируется как (0<=a)<=99, и результат первого сравнения равен или 0, или 1, но не значению a (если, конечно, a не есть 1). Проверить, попадает ли a в диапазон 0...99, можно так:
if (0<=a && a<=99) // ...
Среди новичков распространена ошибка, когда в условии вместо == (равно) используют = (присвоить):
if (a = 7) // ошибка: присваивание константы в условии
// ...
Она вполне объяснима, поскольку в большинстве языков "=" означает "равно". Для транслятора не составит труда сообщать об ошибках подобного рода.
3.2.2 Порядок вычислений
Порядок вычисления подвыражений, входящих в выражение, не всегда определен. Например:
int i = 1;
v[i] = i++;
Здесь выражение может вычисляться или как v[1]=1, или как v[2]=1. Если нет ограничений на порядок вычисления подвыражений, то транслятор получает возможность создавать более оптимальный код. Транслятору следовало бы предупреждать о двусмысленных выражениях, но к сожалению большинство из них не делает этого.
Для операций
&& || ,
гарантируется, что их левый операнд вычисляется раньше правого операнда. Например, в выражении b=(a=2,a+1) b присвоится значение 3. Отметим, что операция запятая отличается по смыслу от той запятой, которая используется для разделения параметров при вызове функций. Пусть есть выражения:
f1(v[i],i++); // два параметра
f2( (v[i],i++) ) // один параметр
Вызов функции f1 происходит с двумя параметрами: v[i] и i++, но порядок вычисления выражений параметров неопределен. Зависимость вычисления значений фактических параметров от порядка вычислений - далеко не лучший стиль программирования. К тому же программа становится непереносимой. Вызов f2 происходит с одним параметром, являющимся выражением, содержащим операцию запятая: (v[i], i++). Оно эквивалентно i++.
Скобки могут принудительно задать порядок вычисления. Например, a*(b/c) может вычисляться как (a*b)/c (если только пользователь видит в этом какое-то различие). Заметим, что для значений с плавающей точкой результаты вычисления выражений a*(b/c) и (a*b)/c могут различаться весьма значительно.
