Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект С++ (Часть 1).doc
Скачиваний:
17
Добавлен:
09.11.2019
Размер:
1.24 Mб
Скачать

Преобразования типов данных

Рассмотрим пример:

Определены переменные

int a = 5;

double b = 7.6;

В программе необходимо подсчитать их сумму a + b.

Внутреннее (машинное) представление типа int и типа double существенно различаются. Существенно различаются и процедуры сложения целых значений и процедуры сложения вещественных значений. Как же тогда сложить целое и вещественное? Выход – преобразовать оба значения к одному и тому же типу данных, а затем выполнить соответствующую операцию. Но если преобразовать значение переменной b к целому типу данных (отбросить дробную часть или округлить до ближайшего целого) результат будет равен либо 12, либо 13, то есть произошла потеря точности. А вот если сначала преобразовать значение a к типу double и сложить их как вещественные значения, тогда точность потеряна не будет (результат будет равен 12.6 и будет вещественного типа). На самом деле так и происходит.

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

В языке C++ различают неявное (автоматическое) и явное преобразование типов данных.

Неявное преобразование типов данных при выполнении операций, подобной рассмотренной выше (и в ряде других случаев), выполняется компилятором по определенным правилам автоматически. В чем же состоят эти правила?

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

  1. Все данные типов char и short int преобразуются к типу int.

  2. Если хотя бы один из операндов имеет тип double, то и другой операнд преобразуется к типу double (если он другого типа); результат вычисления имеет тип double.

  3. Если хотя бы один из операндов имеет тип float, то и другой операнд преобразуется к типу float (если он другого типа); результат вычисления имеет тип float.

  4. Если хотя бы один операнд имеет тип long, то и другой операнд преобразуется к типу long (если он другого типа); результат имеет тип long.

  5. Если хотя бы один из операндов имеет тип unsigned, то и другой операнд преобразуется к типу unsigned (если его тип не unsigned); результат имеет тип unsigned.

Если ни один из случаев 1-5 не имеет места, то оба операнда должны иметь тип int; такой же тип будет и у результата.

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

#include <iostream>

using namespace std;

int main()

{

unsigned a = 5;

int b = 10;

cout << a << " - " << b << " = " << a - b << endl;

system("Pause");

return 0;

}

Результат работы программы: 5 – 10 = 4294967291

Таким образом, несмотря на то, что язык C++ достаточно «снисходителен» к действиям программиста, это требует от программиста еще большей дисциплины в его действиях и четких знаний нюансов языка программирования.

Для исправления ошибки в работе предыдущей программы можно, например, изменить вычисление выражения ab следующим образом: (int) ab или int(a) – b. В этом случае мы получим правильный результат: 5 – 10 = -5.

Здесь было использовано явное преобразование типов данных.

Явное преобразование типов данных осуществляется с помощью соответствующей операции преобразования типов данных, которая имеет один из двух следующих форматов:

(<тип данных>) <выражение> или <тип данных> (<выражение>)

Например:

(int) 3.14 int (3.14)

(double) a или double (a)

(long) (a + 1e5f) long (a + 1e5f)

Подобные преобразования имеют своим исходом три ситуации:

  • преобразование без потерь;

  • с потерей точности;

  • с потерей данных.

Преобразование происходит без потерь, если преобразуемое значение принадлежит множеству значений типа, к которому осуществляется преобразование. Например:

short a = 100;

cout << (int) a << endl; // На экран выведено 100

cout << (char) a << endl; // Выведена буква d (ее десятичный эквивалент - 100)

cout << (float) a << endl; // На экран выведено 100

cout << (double) a << endl; // На экран выведено 100

float b = 3.14f;

cout << (double) b << endl; // На экран выведено 3.14

double d = 3.14;

cout << (float) d << endl; // На экран выведено 3.14

Преобразование любого вещественного типа к целому осуществляется путем отбрасывания дробной части вещественного значения, поэтому практически всегда такие преобразования приводят к потере точности (осуществляются приближенно). Например:

double d = 3.74;

cout << (int) d << endl; // На экран выведено 3

А вот попытки преобразования значений выходящих за пределы диапазона типа данных, к которому осуществляется преобразование, приводят к полному искажению данных. Например:

int a = -100;

cout << (unsigned) a << endl; // На экран выведено 4294967196

int a = 50000;

cout << (short) a << endl; // На экран выведено -15536

float b = 3e+9f;

cout << (int) b << endl; // На экран выведено -2147483648

double d = 3e+9;

cout << (int) d << endl; // На экран выведено -2147483648

double d = 3e+40;

cout << (float) d << endl; // На экран выведено 1.#INF - переполнение

double d = -3e+40;

cout << (float) d << endl; // На экран выведено -1.#INF - переполнение

Рассмотренная операция преобразования типов перешла в C++ из C. В C++ имеются свои операции преобразования типов данных. Например, рассмотренные выше преобразования в C++ можно было бы выполнить с помощью операции static_cast, имеющей следующий формат:

static_cast <тип данных> (выражение)

Например:

static_cast <double> (a + 2e+40f)

Пользоваться явными преобразованиями типов следует очень аккуратно и только там, где это действительно необходимо.

При явном преобразовании типов значения преобразуемых величин на самом деле не изменяются – изменяется только представление этих значений при выполнении действий над ними.