Явное и не явное преобразование типов в С++
Сегодня, в продолжении темы изучения языка программирования С++, я, как и обещал в прошлой публикации, расскажу о преобразовании типов. Расскажу, чем отличается явное и неявное преобразование, в каких случаях это может помочь, а в каких — стать серьёзной проблемой. И что об этом нужно знать.
И так, давайте далеко не отходя от кассы, сразу рассмотрим пример, который я оставил в конце прошлой публикации.
#include <iostream>
#include <string>using namespace std;
int GetID(){
string Re = "19";
return stoi(Re);
}int main(){
setlocale(LC_ALL, "ru_RU.UTF-8");
int ID = GetID();
cout << "ID пользователя: " << ID << endl;
return 0;
}
Что мы тут видим? Мы видим пример реализации функции, которая откуда то получает ID пользователя. И мы представили ситуацию, когда нам вернулось число в виде строки. На самом деле, когда мы перейдём к более приближенным к реальности примерам, мы увидим, что такая ситуация — вполне штатная и сталкиваться с ней вы будете с завидной регулярностью. И если попытаться вернуть число в виде строки — мы просто получим вот такую ошибку:
На самом деле, если постараться, то можно заставить компилятор самостоятельно исправлять подобные ошибки, но чуть позже я покажу пример, почему так делать не стоит.
И так, что делать, чтоб преобразовать число в виде строки, в число, в виде числа? Просто воспользоваться функцией stoi(). Обратите внимание, что перед тем, как воспользоваться функцией, нужно убедиться, что в строке нет ничего, кроме цифр. Конечно, функция может, к примеру, обрезать пробельные символы или символы табуляции, но никак не строки. Т.е.:
- int test = stoi("19"); // Верно
- int test = stoi(" 19 "); // Верно
- int test = stoi("ID 19"); // Ошибка
Теперь давайте рассмотрим такой вариант:
Теперь давайте рассмотрим другой вариант:
#include <iostream>
#include <string>using namespace std;
float GetInt(){
float Re = 18.99;
cout << "Передаём число: " << Re << endl;
return Re;
}int main(){
setlocale(LC_ALL, "ru_RU.UTF-8");
int Get = GetInt();cout << "Получаем число: " << Get << endl;
return 0;
}
Сразу запустим и посмотрим, что получаем:
Как так получилось, что передавали 18.99, почти 19, а получили ровно 18? Думаю те, кто внимательно читал уроки и смотрел код, уже заметили, что в функции GetInt() была создана переменная с типом float, его же функция и вернула, но вот в main(), переменная имеет тип int, который меньше, чем float. По этому в данной переменной места для дробной части просто не хватило. Если сказать проще, тут произошло не явное преобразование типа. И это плохо. Давайте Расскажу пример, когда это может быть плохо.
К примеру, представьте себе ситуацию, когда мы написали программу, которая должна контролировать температуру в помещении, в конфиг файле вы написали, что считывание температуры должно происходить раз в 1,9 секунды. Но из за такой вот ошибки, считывание будет проходить почти в два раза чаще, раз в секунду и вы наверняка, потратите не один час времени в поисках причины, что же не так.
Разумеется, если рассматривать пример с секундами и температурой, исправление будет выглядеть просто. Мы просто в функции main(), строчку int Get = GetInt(); заменим на строчку float Get = GetInt();. Но что делать в ситуации, когда нам нужно именно преобразовать? Сделать это достаточно просто.
#include <iostream>
#include <string>using namespace std;
float GetInt(){
float Re = 18.99;
cout << "Передаём число: " << Re << endl;
return Re;
}int main(){
setlocale(LC_ALL, "ru_RU.UTF-8");
float Get = (int) GetInt();cout << "Получаем число: " << Get << endl;
return 0;
}
Как видим, изменилась всего одна строка: float Get = (int) GetInt();
Но при этом, поведение программы — осталось прежним! Так зачем было менять, спросите вы? А менять — надо! Дело в том, что благодаря добавленному оператору (int), вы сами видите, что функция возвращает другой тип данных, который преобразуется в int. Таким образом вы сами подстраховываете себя от забывчивости. Но что более важно, этим действием, вы говорите компилятору, что вкурсе несоответствия типов и хотите, чтоб он его преобразовал, не выдавая предупреждений.
Но остаётся ещё одна проблема. В данном случае, дробная часть — просто обрезается. Но можно ли сделать, чтоб преобразование происходило более умно? На самом деле — можно. К примеру, воспользовавшись функцией round().
#include <iostream>
#include <string>
#include <math.h>using namespace std;
float GetInt(){
float Re = 18.99;
cout << "Передаём число: " << Re << endl;
return Re;
}int main(){
setlocale(LC_ALL, "ru_RU.UTF-8");
float Get = round(GetInt());cout << "Получаем число: " << Get << endl;
return 0;
}
На самом деле, для округления значений до целого есть целых три функции: round, roundf, roundl, которыми можете воспользоваться в разных ситуациях. Подробнее о них написано тут.
Но обратите внимание. Для того, чтоб воспользоваться ими — нам нужно подключить ещё одну библиотеку. Написать в начале файла: #include <math.h>. И думаю теперь, когда их уже у нас стало три штуки, давайте наверное к ним и перейдём, давайте в следующей публикации уже поговорим о том, что это за магические строчки, которые помогают подключать магические функции, как они выглядят изнутри, и что более важно, попробуем сами написать что то, что можно подключить в виде магической строки.
Комментарий успешно отправлен. Он будет опубликован после проверки модератором.