Неявные преобразования типов часто приводят к ошибкам, которые не всегда легко заметить и быстро обнаружить. Поэтому сегодня я расскажу о новых операторах приведения, которые позволяют более строго оформлять свои мысли и чётче их формулировать. /********************************************************************************************* ********************************************************************************************** *********************************************************************************************/ Первый: const_cast < type > ( return_value ) /* Позволяет добавлять или удалять квалификаторы типов "const" и "volatile" из типов выражения. const Person* getName() { /* тело функции */ } Person* anName = const_cast < Person* > ( getName() ); /* "const_cast" аннулировал "const" в типе значения, возвращаемого функцией getName() */ Эквивалентно худшему варианту: anName = ( Person* ) getName(); Плюсы "const_cast": 1) Он бросается в глаза, поэтому видно, что было преобразование типа. 2) Если будет изменение функции getName из const Person* getName() в const Name* getName(), то компилятор сообщит об этом, так как возможности "const_cast" ограничены. /********************************************************************************************* ********************************************************************************************** *********************************************************************************************/ Второй: static_cast < type > ( return_value ) /* Применяется для переносимых на разные платформы приведений. Чаще всего служит для приведения "вниз" по иерархии наследования от указателя (или ссылки) на базовый класс к указателю (или ссылке) на производный класс. */ Shape* sp = new Circle; Circle* cp = static_cast < Circle* > ( sp ); /* Компилируется, потому что "sp" действительно ссылается на объект "Circle". Но если бы "sp" указывал на какой-нибудь другой тип "Rectangle", то при использовании "cp" получил бы, скорее всего, ошибку. */ Вывод: static_cast не меняет квалификаторы типа так, как это может const_cast const Shape* getShape() { /* тело функции */ } Circle* cp = static_cast < Circle* > ( const_cast <Shape* > ( getShape() ) ); /********************************************************************************************* ********************************************************************************************** *********************************************************************************************/ Третий: reintepret_cast < type > ( type2 ); /* Обычно работает с битами объекта и позволяет осуществлять преобразования между совершенно несвязными типами. */ HP = reinterpret_cast < char* > ( 0x0f0... ) /* преобразует целое в указатель */ /* теперь будем преобразовывать char* в int* */ int* PW = reinterpret_cast < int* > ( HP ); Выводы: 1) Такие преобразования в коде низкого уровня не являются непереносимыми. 2) reinterpret_cast обычно считает, что указатель на базовый класс является указателем на производный класс и не меняет его значение. А static_cast осуществляет правильную работу с адресами. /********************************************************************************************* ********************************************************************************************** *********************************************************************************************/ Четвёртый: dynamic_cast /* Обычно применяется для безопасного нисходящего приведения от указателя на базовый класс к указателю на производный класс. От static_cast отличается тем, что нисходящее преобразование может осуществляться только для полиморфного типа ( то есть тип приводимого выражения должен быть указателем на тип класса с виртуальной функцией ). Правильность приведения проверяется во время выполнения. И если у statc_cast издержки времени минимальны, то dynamic_cast предполагает более существенные издержки времени выполнения. const Circle* cp = dynamic_cast < const Circle* > ( getShape() ); /* Если getShape возвращает указатель на Circle (или какой-то наследуемый от Circle класс), то приведение будет успешным и cp будет указывать на Circle. Иначе cp будет нулевым. Удобно в if ( ) { /* */} поместить объявление "const Circle* ... ". Тогда cp, когда в нём исчезнет необходимость, сам уйдёт из области видимости. const Circle& rc = dynamic_cast < const Circle& > ( *getShape( ) ); /*Приведение аналогично,но вместо возврата нулевого указателя формирует исключение std::bad_cast */ Применение dynamic_cast к указателю это вопрос: "Этот указатель на Shape фактически указывает на Circle? Если нет, я могу заняться этим!" Применение dynamic_cast к ссылке это утверждение: "Предполагается, что этот Shape есть не что иное, как Circle. Если это не так, значит что-то не в порядке!"
|