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

Сайт не является учебником по программированию. Это только небольшой авторский сборник информации в помощь начинающим программистам.

В С++ используется множество типов данных. Под конкретные задачи используют конкретные типы. Так, например, иногда требуются только целые числа, а иногда дробные. Иногда нужно число, а иногда символ. Иногда нужно короткое целое, а иногда длинное целое. Для нас (людей) нет большой разницы, например, при выполнении операции сложения двух коротких целых чисел или сложения двух длинных целых, но компьютер не человек. Для компьютера существуют какие-то аппаратные инструкции, которые писали программисты. Два разных типа могут быть очень похожи, но два разных типа — это два разных типа, и, поэтому, даже одинаковая с виду для них операция, может иметь различные реализации.
Чтобы на нас не сильно влияло такого рода различие реализаций операций для разных типов, в С++ существуют операции приведения типов (преобразования типов), которые зачастую происходят неявно, хотя и явно их можно описывать.

  • С++ преобразует значения при присваивании одного арифметического типа другому арифметическому типу
  • С++ преобразует значения при комбинировании в выражении различными типами
  • С++ преобразует значения при передаче их в функции

С++ Код Преобразование переменных при присваивании

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

Тут как ни посмотри в первый раз, непорядок получается. На первых началах думается, что такое манипулирование числами и переменными — это самая обычная перестановка числа 33,777 в некоторую переменную и возврат её оттуда назад, но мы видим то, что видим. А видим мы, что число усекается. «Переменная поела переменную». Связан этот эффект как раз с преобразованиями переменных. Внимательно смотрим на код и вникаем в в него. Замечаем, что в одном выражении присутствуют переменные разных типов и вспоминаем, что в таком случае, компилятор будет использовать преобразования. Чтобы вам было проще ориентироваться, имеет смысл запомнить такое правило

  • При присваивании левая переменная не приводится к нужному типу, а вот правая приводится к типу переменной, указанной слева (если такое преобразование возможно)

Разберем последний листинг (из 5 строк см. чуть выше) по этому правилу:
Первая нужная нам операция — это операция присваивания.
1. а=b ==> int=double ==> слева int не преобразуется, а справа double преобразуется в int, чтобы операция присвоения стала возможна
2. b=a ==> double=int ==> слева double, справа int, значит int преобразуется в double, чтобы операция присвоения стала возможна.
Таким вот образом, компилятор выполняет некоторые заботы, которые могли бы быть нашей головной проблемой. Но из-за того, что начинающие не видят и не знают, что такое явление — это обычное поведение компилятора С++, то часто мучаются
Само приведение типов срабатывает не только при присвоении значения в переменную, но и при некоторых действиях, например:
6/5.0 ===> 1.2===> результирующая переменная double
В таком выражении нет операции присваивания, но идет комбинирование переменных разных типов. При комбинировании разных типов компилятор может выполнять достаточно большое количество преобразований от типа к типу.
6/5.0+‘g’ ==> В выражении целых три типа, но все они будут приведены к double и в результате работы будет переменная типа double. Это определяется контекстом выражения. Так как в первом выражении целое делится на число с точкой, то компилятор предполагает, что мы хотим получить число с точкой и для лучшего результата отдает нам число с точкой двойной точности (double), дальше в выражении остаются два типа double и char (char представляет из себя такой тип данных, который обрабатывается как целое число), поэтому выражение эквивалентно выражению, где остались две переменные типов double и int. Точно также как и раньше, тип результирующей переменной определяется контекстом выражения. Компилятор решает, что нам нужен double и поэтому приводит тип char к double (чтобы выполнить сложение double+double). В итоге на выходе остается результат, тип которого double.
Очень хорошо будет, если вы поймете как это работает, мне сейчас немного трудно это описывать так, чтобы сходу стало все сразу ясно.

  • Вы должны четко и точно ориентироваться когда произойдет неявное приведение типов

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

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

В некоторых компиляторах C++, которые старше Borland C++ 3.1 можно узнавать тип данных.

О такой возможности можно сказать, что в зависимости от реализации компилятора, результаты на экране могут быть разными, но Стандарт C++ гарантирует, что для значений с одинаковыми типами, возвращаемые строки будут одинаковыми.

Полный пример использования в CodeBlocks (MinGW)

Можно побаловаться и посмотреть как и когда преобразует. Еще один вариант кода (со своими недостатками)

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

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

Одна из очень часто встречающихся ошибок, связанных с преобразованиями связана с делением целых чисел
5/4 отдает 1
Здесь 2 типа данных int и int, так как типы одинаковые, то компилятор не считает нужным преобразовывать их, так как и без преобразований операции между одинаковыми типами выполнится должны без проблем.
Другая очень часто встречающаяся ошибка связана с переменной типа char. Например, очень часто пытаются сравнивать char с числом в диапазоне 0..9, а не с символом

Когда мы вводим число 8 с клавиатуры и оно запоминается в переменную ch, происходит неявное преобразование символа ‘8’ к числу. Числовое значение этого символа 56 и поэтому если сравнивать ch с числом, то сравнивать надо с числом 56, но если сравнивать с символом, то сравнивать надо с символом ‘8’ (символ всегда внутри одинарных кавычек).

На первых порах эту тему немного тяжело понимать, но избежать ее у вас не получится. Нужно хорошо ориентироваться в переменных и типах данных, понимать различие между типами, ограничения типов. Если это понимаете, то данную тему понять будет чуть проще.
(возможно буду что-то дописывать еще сюда, но надеюсь уже сейчас получилось хорошо)

Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

2 комментария: С++ Неявное преобразования типов

  • Ann говорит:

    А можно подробней как работает это метод:
    void type(T ch)

    Автор сайта отвечает:
    Да, можно. Только это другая тема.
    T обозначает параметр типа, который компилятор сам приписывает. Тема называется шаблоны функций.
    Там запись типа такой должна быть

    Тип ch теперь всегда будет таким, каким его передали в функцию type
    Но нужно вам читать шаблоны функций.

  • FeelTerr говорит:

    ispravte, pojaluista:

    но если сравнивать с символом, то сравнивать надо с символом ’8′

    na

    но если сравнивать с символом, то сравнивать надо с символом '8'

    P.S.: spasibo za vash trud, i prostite za translit, net russkoi rasskladki i klaviatury 🙂

Добавить комментарий

Ваш e-mail не будет опубликован.

Поиск

 
     
Яндекс.Метрика

НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

-Папа, а что такое "высшее образование"? -Это то, что в 80-х годах прошлого века называлось "среднее"..

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок