Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
85
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

149

 

 

(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 )

 

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

 

С++ для начинающих

150

 

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] или любую книгу по математике.) Например, можно написать:

С++ для начинающих

151

#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);

или эквивалентный синтаксис вызова функции:

С++ для начинающих

152

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;

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

С++ для начинающих

153

#include <complex> inline complex<double>&

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

{

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

}

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

Используя этот пример, реализуйте три других составных оператора присваивания для типа complex<double>. Добавьте свою реализацию к программе, приведенной ниже, и

#include <iostream> #include <complex>

// определения операций...

int main() {

complex< double > cval ( 4.0, 1.0 );

cout << cval << endl; cval += 1;

cout << cval << endl; cval -= 1;

cout << cval << endl; cval *= 2;

cout << cval << endl; cout /= 2;

cout << cval << endl;

запустите ее для проверки.

}

Упражнение 4.10

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

cval += 1;

что означает увеличение на 1 вещественной части cval, то и операция инкремента выглядела бы вполне законно. Реализуйте эти операции для типа complex<double> и выполните следующую программу: