Static cast c что это

Оператор static_cast

Преобразует выражение в тип типа-ID, основанный только на типах, имеющихся в выражении.

Синтаксис

Remarks

В стандартном языке C++, проверка типа во время выполнения не выполняется, что обеспечивает безопасность преобразования. В C ++/CX выполняются проверки во время компиляции и во время выполнения. Дополнительные сведения см. в разделе Приведение.

static_cast Оператор можно использовать для таких операций, как преобразование указателя на базовый класс в указатель на производный класс. Такие преобразования не всегда являются безопасными.

dynamic_cast Операторы и static_cast перемещают указатель на всю иерархию классов. Однако static_cast полагается исключительно на информацию, предоставленную в инструкции CAST, и поэтому может быть ненадежной. Пример:

Если pb указывает на объект типа, B а не на полный D класс, то dynamic_cast будет достаточно, чтобы вернуть ноль. Однако static_cast полагается на утверждение программиста, которое pb указывает на объект типа D и просто возвращает указатель на этот предполагаемый D объект.

Следовательно, static_cast может выполнить обратное преобразование неявных преобразований, в этом случае результаты будут неопределенными. Программисту остается убедиться, что результаты static_cast преобразования являются надежными.

static_cast Оператор также можно использовать для выполнения любого неявного преобразования, включая стандартные преобразования и пользовательские преобразования. Пример:

static_cast Оператор может явно преобразовать целочисленное значение в тип перечисления. Если значение типа целого не оказывается в диапазоне значений перечисления, получаемое значение перечисления не определено.

static_cast Оператор преобразует нулевое значение указателя в значение указателя null целевого типа.

C++/CLI: Из-за опасности возникновения непроверенных приведений на вершине повторного обнаружения сборщика мусора использование класса должно быть только в критическом для производительности коде, только если вы уверены, что он будет работать правильно. Если необходимо использовать static_cast в режиме выпуска, замените его static_cast в отладочных сборках, чтобы убедиться в успешном выполнении.

Источник

Еще раз про приведение типов в языке С++ или расстановка всех точек над cast

Static cast c что это. 39f2cb6bad01443faeeda391a0601689. Static cast c что это фото. Static cast c что это-39f2cb6bad01443faeeda391a0601689. картинка Static cast c что это. картинка 39f2cb6bad01443faeeda391a0601689

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

Приведение типов в стиле языка C (C-style cast)

Приведение типов в стиле языка C может привести выражение любого типа к любому другому типу данных (исключение это приведение пользовательских типов по значению, если не определены правила их приведения, а также приведение вещественного типа к указателю или наоборот). К примеру, unsigned int может быть преобразован к указателю на double. Данный метод приведения типов может быть использован в языке C++. Однако, метод приведения типов в стиле языка C не делает проверки типов на совместимость, как это могут сделать static_cast и dynamic_cast на этапе компиляции и на этапе выполнения соответственно. При этом все, что умеют const_cast и reinterpret_cast данный метод приведения типов делать может.

Общий вид приведения:

, где new_type – новый тип, к которому приводим, а exp – выражение, которое приводится к новому типу.

Т.к. данный оператор не имеет зарезервированного ключевого слова (например, static_cast) найти все места приведения типов в тексте программы будет не очень удобно, если это потребуется.

const_cast

Оператор приведения const_cast удаляет или добавляет квалификаторы const и volatile с исходного типа данных (простые типы, пользовательские типы, указатели, ссылки). Например, был const int, а после преобразования стал int или наоборот. Квалификаторы const и volatile называют cv-квалификаторы (cv-qualifiers). Данные квалификаторы указываются перед именами типов. Как ни трудно догадаться квалификатор const задает константность, т.е. защищает переменную от изменения. Квалификатор volatile говорит о том, что значение переменной может меняться без явного выполнения присваивания. Это обеспечивает защиту от оптимизации компилятором операций с данной переменной.

Общий вид приведения:

Дополнительный пример от пользователя 5nw

reinterpret_cast

Оператор приведения reinterpret_cast используется для приведения несовместимых типов. Может приводить целое число к указателю, указатель к целому числу, указатель к указателю (это же касается и ссылок). Является функционально усеченным аналогом приведения типов в стиле языка С. Отличие состоит в том, что reinterpret_cast не может снимать квалификаторы const и volatile, а также не может делать небезопасное приведение типов не через указатели, а напрямую по значению. Например, переменную типа int к переменной типа double привести при помощи reinterpret_cast нельзя.

Общий вид приведения:

static_cast

Оператор приведения static_cast применяется для неполиморфного приведения типов на этапе компиляции программы. Отличие static_cast от приведения типов в стиле языка C состоит в том, что данный оператор приведения может отслеживать недопустимые преобразования, такие как приведение указателя к значению или наоборот (unsigned int к указателю на double не приведет), а также приведение указателей и ссылок разных типов считается корректным только, если это приведение вверх или вниз по одной иерархии наследования классов, либо это указатель на void. В случае фиксации отклонения от данных ограничений будет выдана ошибка при компиляции программы. При множественном наследовании static_cast может вернуть указатель не на исходный объект, а на его подобъект.

Общий вид приведения:

dynamic_cast

Оператор приведения dynamic_cast применяется для полиморфного приведения типов на этапе выполнения программы (класс считается полиморфным, если в нем есть хотя бы одна виртуальная функция). Если указатель, подлежащий приведению, ссылается на объект результирующего класса или объект класса производный от результирующего то приведение считается успешным. То же самое для ссылок. Если приведение невозможно, то на этапе выполнения программы будет возвращен NULL, если приводятся указатели. Если приведение производится над ссылками, то будет сгенерировано исключение std::bad_cast. Несмотря на то, что dynamic_cast предназначен для приведения полиморфных типов по иерархии наследования, он может быть использован и для обычных неполиморфных типов вверх по иерахии. В этом случае ошибка будет получена на этапе компиляции. Оператор приведения dynamic_cast приводить к указателю на void, но не может приводить указатель на void к другому типу. Способность dynamic_cast приводить полиморфные типы обеспечивается системой RTTI (Run-Time Type Identification), которая позволяет идентифицировать тип объекта в процессе выполнения программы. При множественном наследовании dynamic_cast может вернуть указатель не на исходный объект, а на его подобъект.

Источник

Урок №171. Динамическое приведение типов. Оператор dynamic_cast

Обновл. 15 Сен 2021 |

На уроке о явном преобразовании типов данных мы рассматривали использование оператора static_cast для конвертации переменных из одного типа данных в другой. На этом уроке мы рассмотрим еще один оператор явного преобразования — dynamic_cast.

Зачем нужен dynamic_cast?

Применяя полиморфизм на практике вы часто будете сталкиваться с ситуациями, когда у вас есть указатель на родительский класс, но вам нужно получить доступ к данным, которые есть только в дочернем классе. Например:

В этой программе метод getObject() всегда возвращает указатель класса Parent, но этот указатель может указывать либо на объект класса Parent, либо на объект класса Child. В случае, когда указатель указывает на объект класса Child, как мы будем вызывать Child::getName()?

Один из способов — добавить виртуальную функцию getName() в класс Parent (чтобы иметь возможность вызывать переопределение через объект класса Parent). Но, используя этот вариант, мы будем загромождать класс Parent тем, что должно быть заботой только класса Child.

Язык C++ позволяет нам неявно конвертировать указатель класса Child в указатель класса Parent (фактически, это и делает getObject()). Эта конвертация называется приведением к базовому типу (или «повышающим приведением типа»). Однако, что, если бы мы могли конвертировать указатель класса Parent обратно в указатель класса Child? Таким образом, мы могли бы напрямую вызывать Child::getName(), используя тот же указатель, и вообще не заморачиваться с виртуальными функциями.

Оператор dynamic_cast

В языке C++ оператор dynamic_cast используется именно для этого. Хотя динамическое приведение позволяет выполнять не только конвертацию указателей родительского класса в указатели дочернего класса, это является наиболее распространенным применением оператора dynamic_cast. Этот процесс называется приведением к дочернему типу (или «понижающим приведением типа»).

Использование dynamic_cast почти идентично использованию static_cast. Вот функция main() из вышеприведенного примера, где мы используем dynamic_cast для конвертации указателя класса Parent обратно в указатель класса Child:

Источник

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

В этом документе описаны распространенные проблемы преобразования типов и описывается, как избежать их использования в коде C++.

Когда компилятор обнаруживает ненадежное преобразование, он выдает ошибку или предупреждение. Произошла ошибка при остановке компиляции. Предупреждение позволяет продолжить компиляцию, но указывает на возможную ошибку в коде. Однако даже если программа компилируется без предупреждений, она по-прежнему может содержать код, который вызывает неявные преобразования типов, приводящие к неправильным результатам. Ошибки типов также могут вводиться явными преобразованиями или приведениями в коде.

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

Если выражение содержит операнды различных встроенных типов и явные приведения отсутствуют, компилятор использует встроенные стандартные преобразования для преобразования одного из операндов, чтобы типы совпадали. Компилятор пытается выполнить преобразования в четко определенной последовательности, пока она не завершится успешно. Если выбранное преобразование является повышением, компилятор не выдает предупреждение. Если преобразование является узким, компилятор выдает предупреждение о возможной утрате данных. Происходит ли фактическая потери данных, зависит от фактических значений, но рекомендуется считать это предупреждение как ошибку. Если включен определяемый пользователем тип, компилятор пытается использовать преобразования, указанные в определении класса. Если не удается найти допустимое преобразование, компилятор выдает ошибку и не компилирует программу. Дополнительные сведения о правилах, регулирующих стандартные преобразования, см. в разделе стандартные преобразования. Дополнительные сведения о пользовательских преобразованиях см. в разделе пользовательские преобразования (C++/CLI).

Расширяющие преобразования (продвижение)

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

Сужающие преобразования (приведение)

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

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

В следующем примере кода показаны некоторые неявные сужающие преобразования и предупреждения, которые возникают компилятором.

Преобразования со знаком — без знака

Компилятор не предупреждает о неявных преобразованиях между целыми типами со знаком и без знака. Поэтому рекомендуется полностью избегать беззнаковых преобразований. Если вы не можете избежать их, добавьте проверку среды выполнения, чтобы определить, является ли преобразуемое значение большим или равным нулю и меньше или равно максимальному значению типа со знаком. Значения в этом диапазоне будут передаваться из входных файлов в неподписанный или из неподписанных в подписывание без переинтерпретации.

Преобразования указателей

Явные преобразования (приведения)

С помощью операции приведения можно указать компилятору преобразовать значение одного типа в другой тип. В некоторых случаях компилятор вызовет ошибку, если эти два типа полностью не связаны, но в других случаях не вызывает ошибку, даже если операция не является строго типизированной. Используйте приведение с осторожностью, так как любое преобразование из одного типа в другой является потенциальным источником ошибок программы. Однако иногда требуется выполнить приведения, а не все приведения являются опасными. Одно эффективное использование приведения заключается в том, что в коде выполняется понижающие преобразования и известно, что преобразование не приводит к созданию неверных результатов в программе. Фактически, это говорит компилятору о том, что вы делаете, а также о том, что вы выполняете предупреждения. Другой способ заключается в приведении из класса указателя на класс, производный от указатель на базовый. Другой способ — приведение к переменной постоянной, чтобы передать ее в функцию, для которой требуется аргумент, не являющийся константой. Большинство этих операций приведения к некоторым рискам требует определенного риска.

В программировании в стиле C для всех типов приведений используется один и тот же оператор приведения в стиле C.

Этот оператор приведения не используется так часто, как другие, и не гарантирует перенос в другие компиляторы.

Дополнительные сведения см. в разделе оператор.

Источник

За кулисами C++: статическое, реинтерпретирующее приведения типов и приведение типов в стиле C

Вы когда-нибудь задумывались, почему приведения типов в стиле C и приведения reinterpret_cast считаются злом? Давайте подробно разберемся, что с ними не так.

Введение

C++ знает 5 разных приведений типов (да, приведение в стиле C не является reinterpret_cast ):

Практическое правило должно быть следующим: никогда не используйте reinterpret_cast или приведение в стиле C; если вам нужно выполнить приведение указателей, выполняйте их приведение через void* и только в случае крайней необходимости используйте reinterpret_cast – что означает, что вам действительно нужно реинтерпретировать данные. Помните, C++ – это экспертный язык, он дает вам полный контроль над вашей машиной, но с силой приходит ответственность!

Пример

Давайте посмотрим, почему «жесткие» приведения на самом деле зло, и почему их следует избегать, как чумы. В этом примере мы предположим следующую иерархию классов:

Теперь рассмотрим следующий код:

Что происходит? Что ж, 1 будет с треском провалиться, 2 будет работать, и 3 зависит от того, правильно ли вы включили заголовок или просто определили типы! Давайте сначала посмотрим на (1): он не работает, потому что указатель ParentWitoutVTable* указывает не на начало вновь созданного объекта Derived в памяти, а на другое место. Например, Visual C++ в качестве первого элемента класса помещает указатель таблицы виртуальных методов, поэтому реальный макет Derived выглядит примерно так:

Изменение порядка, в котором Derived наследуется от своих родителей, не решает эту проблему. Стандарт C++ не дает никаких гарантий, как будут располагаться члены:

порядок наследования не имеет значения, за исключением случаев, указанных в семантике инициализации конструктором (12.6.2), очисткой (12.4) и разметкой хранилища (9.2, 11.1).

и в упомянутом абзаце говорится:

Требования выравнивания реализации могут привести к тому, что два соседних элемента не будут размещены сразу после друг друга; так же возможны требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).

По сути, компилятор может разместить таблицу виртуальных функций там, где он хочет – например, Visual C++ всегда первой размещает таблицу виртуальных функций, независимо от того, в каком порядке класс наследуется от родителей.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *