- •Глава 6 посвящена понятию производных классов, которое позволяет строить
- •Раздел 3.4 главы 2. Для обозначения справочного руководства применяется
- •1991 Г.Г. (такие как множественное наследование, статические функции-члены
- •1.1 Введение
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.5 Объектно-ориентированное программирование
- •1.5 Поддержка объектно-ориентированного программирования
- •1.5.1 Механизм вызова
- •1.5.2 Проверка типа
- •1.5.3 Множественное наследование
- •1.6 Пределы совершенства
- •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.1 Введение
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •4.6.3 Передача параметров
- •5.1 Введение и краткий обзор
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •Vector и matrix, мы могли бы обойтись без контроля индекса при
- •5.4.5 Указатели на члены
- •5.4.6 Структуры и объединения
- •5.5.3 Свободная память
- •5.5.5 Массивы объектов класса
- •6.1 Введение и краткий обзор
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.4.1 Монитор экрана
- •6.5 Множественное наследование
- •7.1 Введение
- •7.3 Пользовательские операции преобразования типа
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.5 Большие объекты
- •Void f2(t a) // вариант с контролем
- •Void f3(t a) // вариант с контролем
- •Inv() обращает саму матрицу m, а не возвращает новую, обратную m,
- •7.13 Предостережения
- •8.1 Введение
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.7.1 Задание реализации с помощью параметров шаблона
- •9.1 Обработка ошибок
- •9.1.2 Другие точки зрения на особые ситуации
- •9.3.2 Производные особые ситуации
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.4.4 Особые ситуации и конструкторы
- •9.5 Особые ситуации могут не быть ошибками
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.4.1.2 Поля вывода
- •10.4.1.4 Вывод целых
- •Istream - шаблон типа smanip, а smanip - двойник для ioss.
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •X Целый параметр выдается в шестнадцатеричной записи;
- •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 Проектирование и язык программирования.
- •12.1.1 Игнорирование классов
- •12.1.2 Игнорирование наследования
- •12.1.3 Игнорирование статического контроля типов
- •12.1.4 Гибридный проект
- •12.2 Классы
- •12.2.1 Что представляют классы?
- •12.2.2 Иерархии классов
- •12.2.3 Зависимости в рамках иерархии классов.
- •Vertical_scrollbar или с помощью одного типа scrollbar, который
- •12.2.6 Отношения использования
- •12.2.7 Отношения внутри класса
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •13.1 Введение
- •13.2 Конкретные типы
- •13.4 Узловые классы
- •1, 2, 6 И 7. Класс, который не удовлетворяет условию 6, походит
- •13.5.1 Информация о типе
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.10 Управление памятью
3.2 Сводка операций
Полное и подробное описание операций языка С++ дано в $$R.7. Советуем
прочитать этот раздел. Здесь же приводится краткая сводка операций и
несколько примеров. Каждая операция сопровождается одним или
несколькими характерными для нее именами и примером ее использования.
В этих примерах 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. Пример
операции || был дан в $$3.2.1, а пример операции && есть в $$3.3.1.
Отметим, что операция запятая отличается по смыслу от той запятой, которая
используется для разделения параметров при вызове функций. Пусть есть
выражения:
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)/ могут
различаться весьма значительно.
