Понятие выражения. Операция присваивания =. Преобразование и приведение типов. Инициализация. Унифицированная инициализация
Содержание
- 1. Что называется выражением в языках программирования?
- 2. Какой общий вид операции присваивания? Примеры
- 3. Как используется операция присваивания при инициализации переменных? Примеры
- 4. Понятие преобразования типа. Классификации преобразований типов
- 5. Классификация по диапазону значений при преобразовании типов
- 6. Классификация по способу преобразования. Неявное и явное преобразование типов
- 7. Правила преобразования типов в выражениях
- 8. Как осуществляются преобразования, которые связаны с типом bool?
- 9. Какой общий вид операции явного приведения типа?
- 10. Что такое унифицированная (списковая) инициализация?
- 11. Как работает унифицированная (списковая) инициализация в случае приведения более широкого типа к менее широкому? Для чего нужна унифицированная инициализация?
- 12. Какие особенности применения круглых скобок и символов «пробел» в выражениях?
- Связанные темы
Поиск на других ресурсах:
1. Что называется выражением в языках программирования?
Выражение – это объединение операторов, литералов и переменных. Выражения используются для проведения вычислений, некоторых действий и т.д. В выражениях могут использоваться имена функций.
Примеры выражений.
a*8+5 Math::Sqrt(x)+Math::Sin(x+2) sigma + gamma/20.0
⇑
2. Какой общий вид операции присваивания? Примеры
Операция присваивания используется для задания некоторого значения переменной. Значение, которое присваивается может быть результатом некоторого выражения.
В языке C/C++ операция присваивания обозначается символом = (равно).
Общий вид операции присваивания:
переменная = выражение;
где
- переменная – имя переменной, которой присваивается значение выражения;
- выражение – некоторое выражение, которое может быть использовано согласно синтаксису языка C/C++.
Примеры операции присваивания.
a = 8;
b = a + Math::Sqrt(x)+Math::Sin(x+2);
sigma = (double) (2.0 / 8);
⇑
3. Как используется операция присваивания при инициализации переменных? Примеры
Общий вид операции присваивания при инициализации переменных:
тип имя_переменной = выражение_или_значение;
где
- тип – тип переменной, которая инициализируется;
- выражение_или_значение – значение выражения или константная величина. Если используется значение выражения, то переменные, входящие в это выражение должны быть уже объявлены на данный момент (см. пример).
Примеры инициализации переменных.
... // Инициализация переменных int a = 8, b = 25; double c = 3.550093; bool f = false; char sym = 'A'; // Инициализация переменных с выражением float x = 3.5; float y = x + 2.8; float z = x*x + y*y*y; float zz = Math::Sqrt(z+5.0); ...
⇑
4. Понятие преобразования типа. Классификации преобразований типов
Часто в выражениях фигурируют переменные различных типов. В таких случаях компилятор выполняет так называемое приведение или преобразование одного типа в другой. В C ++ существуют следующие классификации преобразований типов:
- классификация по диапазону значений;
- классификация по способу преобразования.
⇑
5. Классификация по диапазону значений при преобразованиии типов
При классификации по диапазону значений различают:
- сужающее преобразование типов. В этом случае больший тип данных сужается к меньшему (сужается диапазон значений). Здесь может возникнуть потеря данных;
- расширяющее преобразования типов. При таком преобразовании меньший тип данных расширяется до большего типа данных (расширяется диапазон значений).
Следующие примеры демонстрируют эти два вида преобразований.
Пример 1. Демонстрируется сужающее преобразование типов.
// 1. Сужающее преобразование данных, приводящее к потере данных // При инициализации переменной int d = 5.85; // тип double сужается к типу int, d = 5 cout << "d = " << d << endl; // d = 5 - происходит потеря данных // При присваивании в выражении int k; k = 2.3 + 0.5 + 0.1; // тип double сужается к типу int cout << "k = " << k << endl; // k = 2 - происходит потеря данных // 2. Сужающее преобразование без потери данных short f = 2000; // тип int сужается к типу short cout << "f = " << f << endl; // f = 2000
Как видно из примера, при сужающем преобразовании типов возможна потеря данных.
Пример 2. Демонстрируется расширяющее преобразование типов.
// Расширяющее преобразование типов unsigned int t = 4000000000; // int расширяется к unsigned int без ошибок cout << "t = " << t << endl;
В примере значение 4000000000 имеет тип int. Это значение корректно расширяется к типу unsigned int.
Если тип переменной t указать как int
int t = 4000000000; // число 4000000000 не поместится в тип int, t = -294967296 - потеря данных
то значение t буде равно -294967296. Это значит, что число 4000000000 не поместится в тип int.
⇑
6. Классификация по способу преобразования. Неявное и явное преобразование типов
В зависимости от направления преобразования, это преобразование может быть реализовано одним из двух способов:
- неявное преобразование. Это преобразование называют автоматическим. Неявное преобразование компилятор выполняет самостоятельно без вмешательства программиста;
- явное преобразование или приведение типов. В данном случае в скобках вписывается тип преобразования.
Пример.
// 1. Неявное преобразование типов int a = 25; double x; x = a; // неявное преобразование int => double float y = 78.3; // неявное преобразование double => float // 2. Явное преобразование типов int b; b = (int)8.6; // b = 8, явное преобразование double => int float z = (float)12.55; // явное преобразование double => float
⇑
7. Правила преобразования типов в выражениях
Если в выражении встречаются два операнда разных типов, то действуют следующие правила:
- все операнды преобразуются к типу самого наибольшего операнда. Процесс такого преобразования называется расширением типа (integral promotion);
- все типы char и short int преобразуются к типу int. Процесс такого преобразования называется целочисленным расширением (integer promotion);
- если один из операндов имеет тип double, тогда любой другой операнд приводится к типу double. Даже, в случае с типом char, происходит приведение к типу double;
- после преобразования оба операнда имеют одинаковый тип, который есть типом результата операции.
Ниже приведены примеры автоматического преобразования типов.
Преобразование между типами char и int:
char c; int d; c = 'A'; d = c; // d = 65 d = 67; c = d; // c = 'C'
Преобразование между типами int и float:
int d = 28; float x; x = d; // x = 28.0 - тип float d = 5.0 + 5; // d = 10 - тип int
Преобразование между типами float и double
float f; double d; int size; f = 2.54f; d = f; // d = 2.54 - типа double d = 2.0f + 8.5; // результат типа double
⇑
8. Как осуществляются преобразования, которые связаны с типом bool?
Если выражение содержит целочисленный тип, то значения типа bool автоматически превращаются в целые числа 0 и 1. Значению 0 соответствует значение false. Значению 1 или ненулевому значению соответствует значение true.
Пример. Фрагмент кода, который демонстрирует преобразование для типа bool
bool b; int a; a = 0; b = a; // b = False a = 1; b = a; // b = True a = 50; b = a; // b = True
⇑
9. Какой общий вид операции явного приведения типа (type)?
Общий вид операции приведения типа:
(тип) выражение
где тип – тип, к которому нужно привести результат вычисления выражения.
Примеры использования операции явного приведения типов.
int a; float x; a = 5; x = a/2; // x = 2.0 x = (float)(a/2); // x = 2.0 x = (float)a/2; // x = 2.5 - типа float x = a/2.0; // x = 2.5 - типа float x = (int) (8/3.0); // x = 2 x = (float) (8/3.0); // x = 2.666667
Рекомендация. С целью получения необходимой точности при вычислении выражений, содержащих целочисленные и вещественные значения, желательно всегда делать операцию приведения типа к типу переменной, которой присваивается значение.
⇑
10. Что такое унифицированная (списковая) инициализация? Пример
Унифицированная инициализация еще называется списковой инициализацией. Этот вид инициализации переменной был добавлен начиная с версии C++ 11. С помощью унифицированной инициализации можно задать значения переменным, массивам, объектам единообразным способом.
Синтаксически унифицированная инициализация может быть реализована одним из двух способов:
1. С использованием оператора присваивания (=). В этом случае инициализация имеет вид:
type varName = { value };
2. Без использования оператора присваивания. Общий вид такой инициализации следующий:
type varName { value };
В вышеприведенных формах:
- type – тип данных, каким может быть базовый тип (int, double, …), класс, структура, перечисление и т.д.;
- varName – имя инициализируемой переменной;
- value – значение, присваиваемое переменной varName.
Пример унифицированной инициализации переменных разних видов.
#include <iostream> using namespace std; // Структура Point struct Point { int x; int y; }; // Класс Book class Book { public: string title; float price; }; void main() { // Унифицированная (списковая) инициализация // 1. Для одиночной переменной разных типов int i = { 25 }; double x { 7.88 }; float f = { -13.23 }; char c { '+' }; string s { "Hello world" }; bool b = { true }; // 2. Для массива int A[5] { 33 }; // A = { 33, 0, 0, 0, 0 } // 3. Для структуры Point Point pt{ 2, -3 }; // pt.x = 2; pt.y = -3 // 4. Для объекта класса Book Book B{ "The title of book", 99.99f }; }
⇑
11. Как работает унифицированная (списковая) инициализация в случае преобразования более широкого типа к менее широкому? Для чего нужна унифицированная инициализация?
Унифицированная инициализация полезна, когда нужно реализовать проверку корректного приведения типов при инициализации. Унифицированная инициализация обнаруживает ошибки на этапе компиляции в случае, если происходит потеря данных. Потеря данных может возникнуть в случае неявного сужающего преобразования типов.
При унифицированной инициализации компилятор генерирует ошибку:
- когда происходит урезание значения, присваиваемого инициализированной переменной;
- когда присваиваемое значение выходит за пределы допустимых значений типа инициализируемой переменной. Эта ситуация характерна для целочисленных и символьных переменных.
При обычной инициализации (не унифицированной) компилятор допускает потерю данных и не генерирует ошибку.
Следующие примеры демонстрируют назначение унифицированной инициализации.
Пример 1. Пусть задана переменная типа int, которая должна быть инициализирована обычным способом инициализации
int d = 7.88; // d = 7 cout << "d = " << d << endl; // d = 7
В этом случае произойдет неявное сужающее преобразование, поскольку переменной типа int присваивается значение типа double. В результате, значение переменной d будет равно 7.
Если инициализировать переменную d унифицированным способом инициализации
int d = { 7.88 }; // ошибка компиляции!!!
то произойдет ошибка на этапе компиляции с сообщением
conversion from double to int requires a narrowing conversion
Пример 2. В этом примере показано, что унифицированная инициализация позволяет выявлять ошибки потери данных для совместимых типов. Пусть дана переменная типа short, которая инициализируется значением типа int, выходящим за допустимый диапазон типа short
// Обычная инициализация short t = 200000000; // переполнение, ошибки компиляции нет, t = -15872
Здесь компилятор ошибки не генерирует, происходит обычное переполнение и значение 200000000 урезается к типу short.
Если инициализировать переменную t унифицированным способом
// Унифицированная инициализация short t{ 200000000 }; // переполнение, ошибка компиляции
то компилятор выдаст сообщение об ошибке
conversion from int to short requires a narrowing conversion
⇑
12. Какие особенности применения круглых скобок и символов «пробел» в выражениях?
Чтобы улучшить читабельность, в программах используются:
- символы «пробел»;
- символы табуляции (клавиши Tab);
- круглые скобки ( ). Круглые скобки позволяют также повысить приоритет операций, которые помещены в них. Количество круглых скобок не влияет на скорость вычисления выражения.
⇑