Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

где op= является одним из десяти операторов:

 

+=

-=

*=

/=

%=

 

 

 

 

<<=

>>=

&=

^=

|=

 

 

 

 

 

 

 

 

Запись a op= b в точности эквивалентна записи a = a op b. Упражнение 4.6

int main() { float fval; int ival; int *pi;

fval = ival = pi = 0;

Найдите ошибку в данном примере. Исправьте запись.

}

Упражнение 4.7 Следующие выражения синтаксически правильны, однако скорее всего работают не так,

(a)if ( ptr = retrieve_pointer() != 0 )

(b)if ( ival = 1024 )

как предполагал программист. Почему? Как их изменить?

(c)ival += ival + 1;

4.5.Операции инкремента и декремента

Операции инкремента (++) и декремента (--) дают возможность компактной и удобной записи для изменения значения переменной на единицу. Чаще всего они используются при работе с массивами и коллекциями – для изменения величины индекса, указателя или итератора:

#include <vector> #include <cassert>

int main()

{

int ia[10] = {0,1,2,3,4,5,6,7,8,9}; vector<int> ivec( 10 );

int ix_vec = 0, ix_ia = 9; while ( ix_vec < 10 )

ivec[ ix_vec++ ] = ia[ ix_ia-- ];

int *pia = &ia[9]; vector<int>::iterator iter =

ivec.begin();

while ( iter != ivec.end() ) assert( *iter++ == *pia-- );

}

Выражение

ix_vec++

является постфиксной формой оператора инкремента. Значение переменной ix_vec увеличивается после того, как ее текущее значение употреблено в качестве индекса. Например, на первой итерации цикла значение ix_vec равно 0. Именно это значение применяется как индекс массива ivec, после чего ix_vec увеличивается и становится равным 1, однако новое значение используется только на следующей итерации. Постфиксная форма операции декремента работает точно так же: текущее значение ix_ia берется в качестве индекса для ia, затем ix_ia уменьшается на 1.

Существует и префиксная форма этих операторов. При использовании такой формы текущее значение сначала уменьшается или увеличивается, а затем используется новое

//неверно: ошибки с границами индексов

в

//обоих случаях

int ix_vec = 0, ix_ia = 9; while ( ix_vec < 10 )

значение. Если мы пишем:

ivec[ ++ix_vec ] = ia[ --ix_ia ];

значение ix_vec увеличивается на единицу и становится равным 1 до первого использования в качестве индекса. Аналогично ix_ia получает значение 8 при первом использовании. Для того чтобы наша программа работала правильно, мы должны

// правильно

int ix_vec = -1, ix_ia = 8;

while ( ix_vec < 10 )

скорректировать начальные значения переменных ix_ivec и ix_ia:

ivec[ ++ix_vec ] = ia[ --ix_ia ];

В качестве последнего примера рассмотрим понятие стека. Это фундаментальная абстракция компьютерного мира, позволяющая помещать и извлекать элементы в последовательности LIFO (last in, fist out – последним вошел, первым вышел). Стек реализует две основные операции – поместить (push) и извлечь (pop).

Текущий свободный элемент называют вершиной стека. Операция push присваивает этому элементу новое значение , после чего вершина смещается вверх (становится на 1 больше). Пусть наш стек использует для хранения элементов вектор. Какую из форм операции увеличения следует применить? Сначала мы используем текущее значение, потом увеличиваем его. Это постфиксная форма:

stack[ top++ ] = value;

Что делает операция pop? Уменьшает значение вершины (текущая вершина показывает на пустой элемент), затем извлекает значение. Это префиксная форма операции уменьшения:

int value = stack[ --top ];

(Реализация класса stack приведена в конце этой главы. Стандартный класс stack рассматривается в разделе 6.16.)

Упражнение 4.8 Как вы думаете, почему язык программирования получил название С++, а не ++С?

4.6. Операции с комплексными числами

Класс комплексных чисел стандартной библиотеки С++ представляет собой хороший пример использования объектной модели. Благодаря перегруженным арифметическим операциям объекты этого класса используются так, как будто они принадлежат одному из встроенных типов данных. Более того, в подобных операциях могут одновременно принимать участие и переменные встроенного арифметического типа, и комплексные числа. (Отметим, что здесь мы не рассматриваем общие вопросы математики комплексных чисел. См. [PERSON68] или любую книгу по математике.) Например,

#inc1ude <complex>

comp1ex< double > a;

comp1ex< double > b;

// ...

можно написать:

complex< double > с = a * b + a / b;

Комплексные и арифметические типы разрешается смешивать в одном выражении:

complex< double > complex_obj = a + 3.14159;

Аналогично комплексные числа инициализируются арифметическим типом, и им может быть присвоено такое значение:

double dval = 3.14159;

complex_obj = dval;

int ival =

3

;

Или

complex_obj = ival;

Однако обратное неверно. Например, следующее выражение вызовет ошибку

//ошибка: нет неявного преобразования

//в арифметический тип

компиляции:

double dval = complex_obj;

Нужно явно указать, какую часть комплексного числа – вещественную или мнимую – мы хотим присвоить обычному числу. Класс комплексных чисел имеет две функции, возвращающих соответственно вещественную и мнимую части. Мы можем обращаться к

double re = complex_obj.real();

ним, используя синтаксис доступа к членам класса: double im = complex_obj.imag();

double re = real(complex_obj);

или эквивалентный синтаксис вызова функции: double im = imag(complex_obj);

Класс комплексных чисел поддерживает четыре составных оператора присваивания: +=, -=, *= и /=. Таким образом,

complex_obj += second_complex_obj;

Поддерживается и ввод/вывод комплексных чисел. Оператор вывода печатает вещественную и мнимую части через запятую, в круглых скобках. Например, результат выполнения операторов вывода

complex< double > complex0( 3.14159, -2.171 );

comp1ex< double >

complex1( complexO.real() );

cout << complexO << " " << complex1 << endl;

выглядит так:

(3.14159, -2.171 ) ( 3.14159, 0.0 )

//допустимые форматы для ввода комплексного числа

//3.14159 ==> comp1ex( 3.14159 );

//( 3.14159 ) ==> comp1ex( 3.14159 );

//( 3.14, -1.0 ) ==> comp1ex( 3.14, -1.0 );

//может быть считано как

//cin >> a >> b >> с

//где a, b, с - комплексные числа

Оператор ввода понимает любой из следующих форматов:

3.14159 ( 3.14159 ) ( 3.14, -1.0 )

Кроме этих операций, класс комплексных чисел имеет следующие функции-члены: sqrt(), abs(), polar(), sin(), cos(), tan(), exp(), log(), log10() и pow().

Упражнение 4.9

Реализация стандартной библиотеки С++, доступная нам в момент написания книги, не поддерживает составных операций присваивания, если правый операнд не является комплексным числом. Например, подобная запись недопустима:

complex_obj += 1;

(Хотя согласно стандарту С++ такое выражение должно быть корректно, производители часто не успевают за стандартом.) Мы можем определить свой собственный оператор для реализации такой операции. Вот вариант функции, реализующий оператор сложения для

#include <complex> inline complex<double>&

operator+=( complex<double> &cval, double dval )

{

return cval += complex<double>( dval );

complex<double>:

}

(Это пример перегрузки оператора для определенного типа данных, детально рассмотренной в главе 15.)