Приведение типов

Как вы уже знаете, при объявлении переменной необходимо указать определенный тип данных. Далее над переменной можно производить операции, предназначенные для этого типа данных. Если в выражении используются переменные, имеющие разный тип данных, то тип результата выражения будет соответствовать наиболее сложному типу. Например, если производится сложение переменной, имеющей тип int, с переменной, имеющей тип double, то целое число будет автоматически преобразовано в вещественное. Результатом этого выражения будет значение, имеющее тип double.

При попытке присвоить переменной значение, имеющее несовместимый тип, компилятор выведет сообщение об ошибке (если автоматическое преобразование невозможно) или предупреждающее сообщение (при усечении значения). Например, попытка присвоить целочисленной переменной строку (int x = "string";) приведет к ошибке при компиляции:

error: invalid conversion from 'const char*' to 'int'

Попытка присвоить вещественное число целочисленной переменной (int x = 10.5;) приведет к следующему предупреждающему сообщению:

warning: conversion from 'double' to 'int' changes value from '1.05e+1' 
to '10'

В этом случае дробная часть просто отбрасывается, переменной присваивается число 10, а выполнение программы будет продолжено. Чтобы избавиться от предупреждающих сообщений необходимо выполнить явное приведение типов. В этом случае компилятор считает, что вы знаете что делаете.

Для приведения типов в языке C++ используются следующие операторы:

  • static_cast — применяется для стандартного приведения типов. Формат оператора:
static_cast< Тип_результата >(<Выражение>)

Например, деление целых чисел возвращает целое число. Дробная часть при этом просто отбрасывается. Чтобы деление целых чисел возвращало вещественное число, необходимо преобразовать одно из целых чисел в вещественное:

int x = 10, y = 3;
std::cout << x / y << std::endl; // 3
std::cout << static_cast<double>(x) / y 
          << std::endl; // 3.33333
  • reinterpret_cast — используется для приведения указателя одного типа в абсолютно другой, даже в несовместимый. Формат оператора:
reinterpret_cast< Тип_результата >(<Выражение>)
  • const_cast — отменяет действие ключевых слов const и volatile. Формат оператора:
const_cast< Тип_результата >(<Выражение>)

Пример приведения константного указателя в обычный внутри функции:

void func(const int *x) {
   int *p = const_cast<int *>(x);
   // *x = 50; // Ошибка!!!
   *p = 30;    // Теперь можно изменить значение
}

Пример удаления действия ключевого слова const у ссылки внутри функции:

void func(const int &x) {
   // x = 50; // Ошибка!!!
   // Теперь можно изменить значение
   const_cast<int &>(x) = 30;
}
  • dynamic_cast — выполняет приведение типов указателей или ссылок. Применяется для приведения полиморфных типов. Если приведение указателя окончилось неудачей, оператор возвращает нулевой указатель, а если проблема со ссылкой, то генерируется исключение bad_cast (объект исключения объявлен в файле typeinfo). Формат оператора:
dynamic_cast< Тип_результата >(<Выражение>)

Более подробно оператор dynamic_cast мы рассмотрим при изучении объектно-ориентированного программирования в разд. 13.23.

Язык C++ поддерживает также приведение типов, используемое в языке C. Формат приведения:

(<Тип результата>)<Выражение или переменная>

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

short y1 = 1, y2 = 2;
y1 = y1 + y2;
// warning: conversion from 'int' to 'short int' may change value

Чтобы результат выполнения этого выражения не вызывал сомнения компилятора, необходимо выполнить операцию явного приведения типов:

short y1 = 1, y2 = 2;
y1 = (short)(y1 + y2);    // OK

В этом случае компилятор считает, что мы знаем, что делаем, и осведомлены о возможном несоответствии значения указанному типу данных. Если значение выражения будет выходить за диапазон значений типа, то произойдет усечение результата, но никакого сообщения об ошибке не появится. Давайте рассмотрим это на примере:

char c1 = 127, c2 = 0;
c1 = (char)(c1 + c2);    // OK. 127
c1 = 127, c2 = 10;
c1 = (char)(c1 + c2);    // Усечение. -119

Результатом первого выражения будет число 127, которое входит в диапазон значений типа char, а вот результат второго выражения — число 137 — в диапазон не входит, и происходит усечение. В итоге мы получили число –119. Согласитесь, мы получили совсем не то, что хотели. Поэтому приведением типов нужно пользоваться осторожно. Хотя в некоторых случаях такое усечение очень даже полезно. Например, вещественное число можно преобразовать в целое. В этом случае дробная часть просто отбрасывается:

double x = 2.5;
std::cout << x << std::endl;      // 2.5
std::cout << (int)x << std::endl; // 2

Рассмотрим пример, который демонстрирует частый способ применения приведения типов. В языке C++ деление целых чисел всегда возвращает целое число. Дробная часть при этом просто отбрасывается. Чтобы деление целых чисел возвращало вещественное число, необходимо преобразовать одно из целых чисел в вещественное (второе число преобразуется автоматически):

int x = 10, y = 3;
std::cout << x / y << std::endl;          // 3
std::cout << (double)x / y << std::endl;  // 3.33333

Кроме того, можно указать выражение внутри круглых скобок после названия типа:

std::cout << double(10) / 3 << std::endl; // 3.33333

Учебник C++ (MinGW-W64)
Учебник C++ (MinGW-W64) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов