C++. Понятие выражения. Операция присваивания. Преобразование и приведение типов




Понятие выражения. Операция присваивания =. Преобразование и приведение типов. Инициализация. Унифицированная инициализация


Содержание


Поиск на других ресурсах:

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);
  • круглые скобки ( ). Круглые скобки позволяют также повысить приоритет операций, которые помещены в них. Количество круглых скобок не влияет на скорость вычисления выражения.

 


 

Связанные темы