(a) vector vector int ivec;
(b) vector int ivec = { 0, 1, 1, 2, 3, 5, 8 };
(c) vector int ivec( ia, ia+7 );
(d) vector string svec = ivec;
(e) vector string svec( 10, string( "null" ));
Реализуйте следующую функцию:
bool is_equal( const int*ia, int ia_size,
const vectorint ivec );
Функция is_equal() сравнивает поэлементно два контейнера. В случае разного размера контейнеров “хвост” более длинного в расчет не принимается. Понятно, что, если все сравниваемые элементы равны, функция возвращает true, если отличается хотя бы один – false. Используйте итератор для перебора элементов. Напишите функцию main(), обращающуюся к is_equal().
3.11. Класс complex
Класс комплексных чисел complex – еще один класс из стандартной библиотеки. Как обычно, для его использования нужно включить заголовочный файл:
#include complex
Комплексное число состоит из двух частей – вещественной и мнимой. Мнимая часть представляет собой квадратный корень из отрицательного числа. Комплексное число принято записывать в виде
2 + 3i
где 2 – действительная часть, а 3i – мнимая. Вот примеры определений объектов типа complex:
// чисто мнимое число: 0 + 7-i
complex double purei( 0, 7 );
// мнимая часть равна 0: 3 + Oi
complex float rea1_num( 3 );
// и вещественная, и мнимая часть равны 0: 0 + 0-i
complex long double zero;
// инициализация одного комплексного числа другим
complex double purei2( purei );
Поскольку complex, как и vector, является шаблоном, мы можем конкретизировать его типами float, double и long double, как в приведенных примерах. Можно также определить массив элементов типа complex:
complex double conjugate[ 2 ] = {
complex double ( 2, 3 ),
complex double ( 2, -3 )
};
Вот как определяются указатель и ссылка на комплексное число:
complex double *ptr = conjugate[0];
complex double ref = *ptr;
Комплексные числа можно складывать, вычитать, умножать, делить, сравнивать, получать значения вещественной и мнимой части. (Более подробно мы будем говорить о классе complex в разделе 4.6.)
3.12. Директива typedef
Директива typedef позволяет задать синоним для встроенного либо пользовательского типа данных. Например:
typedef double wages;
typedef vectorint vec_int;
typedef vec_int test_scores;
typedef bool in_attendance;
typedef int *Pint;
Имена, определенные с помощью директивы typedef, можно использовать точно так же, как спецификаторы типов:
// double hourly, weekly;
wages hourly, weekly;
// vectorint vecl( 10 );
vec_int vecl( 10 );
// vectorint test0( c1ass_size );
const int c1ass_size = 34;
test_scores test0( c1ass_size );
// vector bool attendance;
vector in_attendance attendance( c1ass_size );
// int *table[ 10 ];
Pint table [ 10 ];
Эта директива начинается с ключевого слова typedef, за которым идет спецификатор типа, и заканчивается идентификатором, который становится синонимом для указанного типа.
Для чего используются имена, определенные с помощью директивы typedef? Применяя мнемонические имена для типов данных, можно сделать программу более легкой для восприятия. Кроме того, принято употреблять такие имена для сложных составных типов, в противном случае воспринимаемых с трудом (см. пример в разделе 3.14), для объявления указателей на функции и функции-члены класса (см. раздел 13.6).
Ниже приводится пример вопроса, на который почти все дают неверный ответ. Ошибка вызвана непониманием директивы typedef как простой текстовой макроподстановки. Дано определение:
typedef char *cstring;
Каков тип переменной cstr в следующем объявлении:
extern const cstring cstr;
Ответ, который кажется очевидным:
const char *cstr
Однако это неверно. Спецификатор const относится к cstr, поэтому правильный ответ – константный указатель на char:
char *const cstr;
3.13. Спецификатор volatile