Операторы позволяют преобразовывать типы данных от одних к другим. Есть пять типов операторов casts:
- c-style cast
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
Рассмотрим каждый из преобразований типов поподробней.
Начнем с явного преобразования типа.
К ним можно отнести такие как:
c-style cast и static_cast
c-style cast
Из названия следует что это пришло из программирования на языке C. Данный метод позволяет осуществить явное преобразование с помощью оператора (). Внутри скобок пишется тип, в который нужно конвертировать.
Пример реализации:
int a =10;
double b =2.14;
double c = (double)a/b;
Данной стиль не проверяется компилятором, поэтому может быть неправильно использован. При преобразование большего типа в меньший случится переполнение.
Данный способ следует использовать с пониманием с осторожностью.
static_cast
Используется для конвертации одного фундаментального типа в другой.
Пример реализации:
char a = 97;
qDebug() << static_cast <int> (a);
В результате будет выведено число 97 а не символ ‘a’.
Данный тип проверяется компилятором во время компиляции.
При использовании операторов явного преобразования в неявном преобразовании приведет к Warning сообщением при компиляции.
Динамическое приведение типов
dynamic_cast
Данный оператор может быть применен к указателям или ссылкам. При применении полиморфизма можно столкнутся с ситуацией, когда есть указатель на родительский класс, но нужно получить доступ к данным которые есть в дочернем классе. В случае если осуществляется преобразование указателя, который содержит адрес объекта-родителя, к указателю типа объекта-потомка, то в результате преобразования будет получен нулевой указатель. При работе с ссылками при неправильном преобразовании будет сгенерировано исключение std::bad_cast.
Проверка корректности приведения типа производится во время выполнения программы.
Фрагмент кода для наглядного примера:
class A {
public:
A() { qDebug() << "A()"; }
virtual ~A() { qDebug() << "~A()"; }
};
class B : public A {
public:
B() { qDebug() << "B()"; }
int test1() {return 1;}
~B() { qDebug() << "~B()"; }
};
A * getObj(bool f)
{
if (f)
return new B();
else
return new A();
}
A * a = getObj(true);
B * b = dynamic_cast<B*>(a);
if (b)
qDebug() << b->test1();
const_cast
Снятия или установка модификатора const. Применяется что бы обойти неудачную архитектуру или не состыковки си с с++.
Фрагмент кода для демонстрации:
int i = 0;
const int& ref = i;
const int* ptr = &i;
const_cast<int&>(ref) = 2;
*const_cast<int*>(ptr) = 3;
qDebug() << i;
qDebug() << ref;
qDebug() << *ptr;
reinterpret_cast
reinterpret_cast — превращает один тип непосредственно в другой — например, приведение значения от одного указателя к другому или сохранение указателя в int. По большому счету, единственная гарантия, которую вы получаете с reinterpret_cast, заключается в том, что обычно, если привести результат обратно к исходному типу, можно получить точно такое же значение (но не в том случае, если промежуточный тип меньше исходного типа). Существует ряд преобразований, которые reinterpret_cast тоже не может выполнить. Он используется главным образом для особенно странных преобразований и битовых манипуляций, таких как превращение потока необработанных данных в реальные данные или хранение данных в младших битах указателя на выровненные данные.
Фрагменты кода:
int a = 1;
std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&a);
qDebug() << v1;
int* p1 = reinterpret_cast<int*>(v1);
Q_ASSERT(p1 == &a);
reinterpret_cast<unsigned int&>(a) = 42;
qDebug() << a;
int test() { return 1; }
void(*test1)() = reinterpret_cast<void(*)()>(test);
int(*test2)() = reinterpret_cast<int(*)()>(test1);
qDebug() << test2();
