Явное преобразование типов

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

Если при вычислении выражения операнды операции имеют разные типы, то возникает необходимость приведения их к одному типу. Такая необходимость возникает и тогда, когда операнды имеют один тип, но он несогласован с типом операции. Например, при выполнении сложения операнды типа byte должны быть приведены к типу int, поскольку сложение не определено над байтами. При выполнении присваивания x=e тип источника e и тип цели x должны быть согласованы. Аналогично, при вызове метода также должны быть согласованы типы источника и цели - фактического и формального аргументов.

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

  • Величины типа char, unsigned char, short или unsigned short преобразуются к типу int, если точность типа int достаточна, в противном случае они преобразуются к типу unsigned int.
  • Величины типа wchar_t и константы перечисленных типов преобразуются к первому из типов int, unsigned int, long и unsigned long, точность которого достаточна для представления данной величины.
  • Битовые поля преобразуются к типу int, если точность типа int достаточна, или к unsigned int, если точность unsigned int достаточна. В противном случае преобразование не производится.
  • Логические значения преобразуются к типу int, false становится 0 и true становится 1.

Эти четыре типа преобразований мы будем называть безопасными преобразованиями.

Язык Си (от которого Си++ унаследовал большинство стандартных преобразований) часто критиковали за излишне сложные правила преобразования типов и за их автоматическое применение без ведома пользователя. Основная рекомендация — избегать неявных преобразований типов, в особенности тех, при которых возможна потеря точности или знака.

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

  • вначале, если в выражении один из операндов имеет тип long double, то другой преобразуется также к long double;
    • в противном случае, если один из операндов имеет тип double, то другой преобразуется также к double;
    • в противном случае, если один из операндов имеет тип float, то другой преобразуется также к float;
    • в противном случае производится безопасное преобразование.
  • затем, если в выражении один из операндов имеет тип unsigned long, то другой также преобразуется к unsigned long;
    • в противном случае, если один из операндов имеет тип long, а другой – unsigned int, и тип long может представить все значения unsigned int, то unsigned int преобразуется к long, иначе оба операнда преобразуются к unsigned long;
    • в противном случае, если один из операндов имеет тип long, то другой преобразуется также к long;
    • в противном случае, если один из операндов имеет тип unsigned, то другой преобразуется также к unsigned;
    • в противном случае оба операнда будут типа int.
(1L + 2.3) результат типа double(8u + 4) результат типа unsigned long

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

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

long x;char c;c = x;

если значение x равно 20, то и c будет равно 20. Но если x равно 500, значение c будет равно -12 (при условии выполнения на персональном компьютере), поскольку старшие биты, не помещающиеся в char, будут обрезаны. Именно поэтому большинство компиляторов выдаст ошибку и не будет транслировать подобные конструкции.