Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cpp_Страуструп.doc
Скачиваний:
16
Добавлен:
03.05.2015
Размер:
3.2 Mб
Скачать

2.3.2 Неявное преобразование типа

В присваивании и выражении основные типы могут совершенно свободно

использоваться совместно. Значения преобразовываются всюду, где

это возможно, таким образом, чтобы информация не терялась. Точные

правила преобразований даны в $$R.4 и $$R.5.4.

Все-таки есть ситуации, когда информация может быть потеряна или

даже искажена. Потенциальным источником таких ситуаций становятся

присваивания, в которых значение одного типа присваивается значению

другого типа, причем в представлении последнего используется

меньше разрядов. Допустим, что следующие присваивания выполняются

на машине, в которой целые представляются в дополнительном коде, и символ

занимает 8 разрядов:

int i1 = 256+255;

char ch = i1 // ch == 255

int i2 = ch; // i2 == ?

В присваивании ch=i1 теряется один разряд (и самый важный!), а когда

мы присваиваем значение переменной i2, у переменной ch значение "все

единицы", т.е. 8 единичных разрядов. Но какое значение примет i2? На

машине DEC VAX, в которой char представляет знаковые значения, это будет

-1, а на машине Motorola 68K, в которой char - беззнаковый,

это будет 255. В С++ нет динамических средств контроля

подобных ситуаций, а контроль на этапе трансляции вообще слишком

сложен, поэтому надо быть осторожными.

2.3.3 Производные типы

Исходя из основных (и определенных пользователем) типов, можно с

помощью следующих операций описания:

* указатель

& ссылка

[] массив

() функция

а также с помощью определения структур, задать другие, производные типы.

Например:

int* a;

float v[10];

char* p[20]; // массив из 20 символьных указателей

void f(int);

struct str { short length; char* p; };

Правила построения типов с помощью этих операций подробно объяснены

в $$R.8. Ключевая идея состоит в том, что описание объекта производного

типа должно отражать его использование, например:

int v[10]; // описание вектора

i = v[3]; // использование элемента вектора

int* p; // описание указателя

i = *p; // использование указуемого объекта

Обозначения, используемые для производных типов, достаточно трудны

для понимания лишь потому, что операции * и & являются префиксными, а

[] и () - постфиксными. Поэтому в задании типов, если приоритеты

операций не отвечают цели, надо ставить скобки. Например, приоритет

операции [] выше, чем у *, и мы имеем:

int* v[10]; // массив указателей

int (*p)[10]; // указатель массива

Большинство людей просто запоминает, как выглядят наиболее часто

употребляемые типы.

Можно описать сразу несколько имен в одном описании. Тогда оно содержит

вместо одного имени список отделяемых друг от друга запятыми

имен. Например, можно так описать две переменные целого типа:

int x, y; // int x; int y;

Когда мы описываем производные типы, не надо забывать, что операции

описаний применяются только к данному имени (а вовсе не ко всем

остальным именам того же описания). Например:

int* p, y; // int* p; int y; НО НЕ int* y;

int x, *p; // int x; int* p;

int v[10], *p; // int v[10]; int* p;

Но такие описания запутывают программу, и, возможно, их следует

избегать.