ivec[ix] = cnt;
Здесь выражения в заголовке цикла for
увеличивают значение итератора ix
и уменьшают значение целочисленной переменной cnt
. Значения итератора ix
и переменной cnt
изменяются при каждой итерации цикла. Пока проверка итератора ix
проходит успешно, следующему элементу присваивается текущее значение переменной cnt
.
Упражнение 4.31. Программа этого раздела использовала префиксные операторы инкремента и декремента. Объясните, почему были использованы префиксные, а не постфиксные версии? Что следует изменить для использования постфиксных версий? Перепишите программу с использованием постфиксных операторов.
Упражнение 4.32. Объясните следующий цикл:
constexpr int size = 5;
int ia[size] = {1,2,3,4,5};
for (int *ptr = ia, ix = 0;
ix != size && ptr != ia+size; ++ix, ++ptr) { /* ... */ }
Упражнение 4.33. Используя таблицу раздела 4.12, объясните, что делает следующее выражение:
someValue ? ++x, ++y : --x, --y
В языке С++ некоторые типы взаимосвязаны. Когда два типа взаимосвязаны, объект или значение одного типа можно использовать там, где ожидается операнд связанного типа. Два типа считаются связанными, если между ними возможно
Для примера рассмотрим следующее выражение, инициализирующее переменную ival
значением 6:
int ival = 3.541 + 3; //
Операндами сложения являются значения двух разных типов: 3.541
имеет тип double
а 3
— int
. Вместо попытки суммирования двух значений разных типов язык С++ определяет набор преобразований, позволяющих преобразовать операнды в общий тип. Эти преобразования выполняются автоматически без вмешательства программиста, а иногда и без его ведома. Поэтому они и называются
Неявные преобразования между арифметическими типами определены так, чтобы по возможности сохранять точность. Как правило, если у выражения есть и целочисленное значение, и значение с плавающей запятой, целое число преобразуется в число с плавающей точкой. В данном случае значение 3
преобразуется в тип double
, осуществляется сложение чисел с плавающей запятой, и возвращается результат типа double
.
Затем происходит инициализация. При инициализации доминирует тип инициализируемого объекта. Поэтому инициализатор преобразуется в его тип. В данном случае результат сложения типа double
преобразуется в тип int
и используется для инициализации переменной ival
. Преобразование типа double
в тип int
усекает значение типа double
, отбрасывая десятичную часть. В данном случае выражение присваивает переменной ival
значение 6
.
Компилятор автоматически преобразует операнды при следующих обстоятельствах.
• В большинстве выражений значения целочисленных типов, меньших, чем int
, сначала преобразуются в соответствующий больший целочисленный тип.
• В условиях нелогические выражения преобразуются в тип bool
.
• При инициализации инициализатор преобразуется в тип переменной; при присвоении правый операнд преобразуется в тип левого.
• В арифметических выражениях и выражениях отношения с операндами смешанных типов происходит преобразование в общий тип.
• Преобразования происходят также при вызове функций, как будет продемонстрировано в главе 6.
long double
, то второй операнд преобразуется тоже в тип long double
независимо от своего типа. Короче говоря, в выражениях, где используются целочисленные значения и значения с плавающей точкой, целочисленное значение преобразуется в соответствующий тип с плавающей точкой.
bool
, char
, signed char
, unsigned char
, short
и unsigned short
преобразуются в int
, если значение соответствует ему, а в противном случае оно преобразуется в тип unsigned int
. Как уже неоднократно упоминалось, значение false
типа bool
преобразуется в 0, a true
в 1.