Операторы позволяют преобразовывать типы данных от одних к другим. Есть пять типов операторов 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();