ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 2) онлайн

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

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

В C++ существует несколько различных операций приведения типов, однако здесь мы ограничимся рассмотрением лишь одной из них.

Явные приведения типов в C++ ведут себя весьма требовательно. Вот при- мер оператора, осуществляющего преобразование типа int к типу char:

aCharVar = static_cast<char>(anIntVar);

 

Здесь переменная, тип которой мы хотим изменить, заключена в круглые скобки, а тип, к которому мы приводим переменную, — в угловые скобки. При- ведение типа переменной anIntVar происходит перед присваиванием значения переменной aCharVar.

Вспомните, как в программе SIGNTEST мы получили неверный результат из-за слишком большого промежуточного значения переменной. Мы решили эту про- блему путем использования типа unsigned int вместо int, поскольку в этом слу- чае диапазон представления оказался достаточным для хранения вычисленного значения. А если бы и этого оказалось недостаточно? Тогда для решения проб- лемы можно использовать операцию приведения типов. Рассмотрим следующий пример.

 

// cast.cpp

// работа со знаковыми и беззнаковыми переменными #include <iostream> using namespace std;

int main() {

int intVar = 1500000000;                 // 1 500 000 000

intVar = (intVar * 10) / 10;             // слишком большой результат

cout << "Значение intVar равно " << intVar << endl;

                                          // неверный результат intVar = 1500000000;                  // приведение к типу double

intVar = (static_cast<double>(intVar) * 10) / 10; cout << "Значение intVar равно " << intVar << endl;

                                          // верный результат

return 0;

}

Когда мы умножаем переменную intVar на 10, получаемый результат, равный 15 000 000 000, нельзя хранить даже с помощью типа unsigned int, поскольку это приведет к получению неверного результата, подобного уже рассмотренному.

Конечно, мы могли бы изменить тип данных на double, которого было бы достаточно для хранения нашего числа, поскольку тип double позволяет хранить

числа длиной до 15 знаков. Но если мы не можем позволить себе подобный вы- ход, например из-за небольшого количества имеющейся в наличии памяти, то существует другой способ — привести переменную intVar перед умножением к типу double. Оператор

static_cast<double>(intVar)

создает временную переменную типа double, содержащую значение, равное зна- чению intVar. Затем эта временная переменная умножается на 10, и поскольку результат также имеет тип double, переполнения не происходит. Затем времен- ная переменная делится на 10, и результат присваивается обычной целой пере- менной intVar. Результат работы программы выглядит следующим образом:

Значение intVar равно 211509811 Значение intVar равно 1500000000

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

До появления стандартного C++ приведение типов осуществлялось в не- сколько ином формате. Если сейчас оператор с приведением типов выглядит так:

aCharVar = static_cast <char>(anIntVar);

то раньше он записывался подобным образом:

aCharVar = (char)anIntVar; или

aCharVar = char(anIntVar);

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

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

 

51