8.1 – Неявное преобразование (принуждение) типов данных

Добавлено 22 мая 2021 в 11:54
Последнее редактирование 20 июня 2021 в 02:14

Введение в преобразование типов

Значение объекта сохраняется как последовательность битов, а тип данных объекта сообщает компилятору, как интерпретировать эти биты в осмысленные значения. Различные типы данных могут по-разному представлять «одно и то же» число. Например, целочисленное значение 3 может быть сохранено как двоичное 0000 0000 0000 0000 0000 0000 0000 0011, тогда как значение с плавающей запятой 3.0 может быть сохранено как двоичное 0100 0000 0100 0000 0000 0000 0000 0000.

Так что же происходит, когда мы делаем что-то подобное?

float f{ 3 }; // инициализируем переменную с плавающей запятой с помощью int 3

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

Процесс преобразования значения из одного типа данных в другой тип данных называется преобразованием типа.

Преобразование типа может быть вызвано одним из двух способов: неявно (по требованию компилятора) или явно (по запросу программиста). В этом уроке мы рассмотрим неявное преобразование типов, а в следующем уроке «8.5 – Явное преобразование (приведение) типов данных и static_cast».

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

Неявное преобразование типа (также называемое автоматическим преобразованием типа или принуждением, англоязычный термин – «coecion») выполняется компилятором автоматически, когда требуется один тип данных, но предоставляется другой тип. Подавляющее большинство преобразований типов в C++ являются неявными преобразованиями типов. Например, неявное преобразование типа происходит во всех следующих случаях:

  • при присвоении или инициализации переменной значением другого типа данных:
    double d{ 3 }; // значение int 3 неявно преобразуется в тип double
    d = 6;         // значение int 6 неявно преобразуется в тип double
  • при использовании бинарного оператора с операндами разных типов:
    double division{ 4.0 / 3 }; // значение int 3 неявно преобразуется в тип double
  • при использование небулевого значения в инструкции if:
    if (5) // значение int 5 неявно преобразуется в тип bool
    {
    }
  • при передаче аргумента функции с типом, отличающимся от типа параметра функции:
    void doSomething(long l)
    {
    }
     
    doSomething(3); // значение int 3 неявно преобразуется в тип long

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

Когда вызывается преобразование типа (неявно или неявно), компилятор определяет, может ли он преобразовать значение из текущего типа в запрашиваемый тип. Если допустимое преобразование может быть найдено, компилятор выдаст новое значение запрашиваемого типа. Обратите внимание, что преобразование типов не меняет значение или тип преобразуемого значения или объекта.

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

// Инициализация с фигурными скобками запрещает преобразования,
// которые приводят к потере данных
int x { 3.5 }; 

Несмотря на то, что компилятор знает, как преобразовать значение типа double в значение типа int, такие преобразования запрещены при использовании инициализации с фигурными скобками.

Бывают также случаи, когда компилятор не может определить, какое из нескольких возможных преобразований типов однозначно является лучшим для использования. Примеры этого мы увидим в уроке «8.11 – Разрешение перегрузки функций и неоднозначные совпадения».

Так как же компилятор на самом деле определяет, может ли он преобразовать значение из одного типа в другой?

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

Стандарт языка C++ определяет, как различные базовые типы (и в некоторых случаях составные типы) могут быть преобразованы в другие типы. Эти правила преобразования называются стандартными преобразованиями.

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

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

В качестве отступления...


Как может быть преобразование типа с нулем преобразований? Например, в архитектурах, где int и long имеют одинаковый размер и диапазон, для представления значений обоих типов используется одна и та же последовательность битов. Следовательно, для преобразования значения между этими типами фактического преобразования не требуется – значение можно просто скопировать.

Полный набор правил, описывающих, как работает преобразование типов, длинен и сложен, и по большей части преобразование типов «просто работает». В следующем наборе уроков мы рассмотрим наиболее важные вещи, которые вам нужно знать о преобразовании типов. Если в каком-то необычном случае требуются более мелкие подробности, полные правила подробно описаны в технической справочной документации для неявных преобразований.

Поехали!

Теги

C++ / CppLearnCppДля начинающихНеявное преобразование типаОбучениеПриведение типовПрограммированиеРасширяющее преобразование типаСужающее преобразование типаЧисловое продвижение

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.