Преобразование типов

Автор: | 23 июля, 2019

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