Оператор static_cast
Преобразует выражение в тип идентификатора типа, основываясь только на типах, присутствующих в выражении.
Синтаксис
static_cast ( expression )
Замечания
В стандартном языке C++, проверка типа во время выполнения не выполняется, что обеспечивает безопасность преобразования. В C ++/CX выполняются проверки во время компиляции и во время выполнения. Дополнительные сведения см. в разделе Приведение.
Оператор static_cast можно использовать для операций, таких как преобразование указателя в базовый класс в указатель на производный класс. Такие преобразования не всегда являются безопасными.
Как правило, вы static_cast используете, когда требуется преобразовать числовые типы данных, такие как перечисления в инты или инты в с плавающей запятой, и некоторые типы данных, участвующие в преобразовании. static_cast преобразования не так безопасны, как dynamic_cast преобразования, так как static_cast не проверка типа времени выполнения. dynamic_cast Неоднозначный dynamic_cast указатель завершится ошибкой, в то время static_cast как возврат, как будто ничего неправильного; это может быть опасно. Хотя dynamic_cast преобразования являются более безопасными, dynamic_cast работает только на указателях или ссылках, а тип времени выполнения проверка является издержками. Дополнительные сведения см. в разделе dynamic_cast Оператор.
В следующем примере строка D* pd2 = static_cast(pb); небезопасна, поскольку D может иметь поля и методы, не входящие в B . Однако строка B* pb2 = static_cast(pd); является безопасным преобразованием, поскольку D всегда содержит все B .
// static_cast_Operator.cpp // compile with: /LD class B <>; class D : public B <>; void f(B* pb, D* pd) < D* pd2 = static_cast(pb); // Not safe, D can have fields // and methods that are not in B. B* pb2 = static_cast(pd); // Safe conversion, D always // contains all of B. >
В отличие от dynamic_cast, проверка времени выполнения не выполняется при static_cast преобразовании pb . Объект, на который указывает pb , может не быть объектом типа D , и в этом случае использование *pd2 может привести ужасным последствиям. Например, вызов функции, являющейся членом класса D , но не класса B , может привести к нарушению прав доступа.
static_cast Операторы dynamic_cast перемещают указатель на всю иерархию классов. Тем не менее, static_cast использует исключительно информацию, указанную в заявлении приведения, и поэтому может быть небезопасной. Например:
// static_cast_Operator_2.cpp // compile with: /LD /GR class B < public: virtual void Test()<>>; class D : public B <>; void f(B* pb) < D* pd1 = dynamic_cast(pb); D* pd2 = static_cast(pb); >
Если pb действительно указывает на объект типа D , pd1 и pd2 получат одно и то же значение. Также они получат одно и то же значение, если pb == 0 .
Если pb указывает на объект типа B , а не на полный D класс, то dynamic_cast будет известно достаточно, чтобы вернуть ноль. Однако, полагается на утверждение программиста, static_cast указывающее pb на объект типа D и просто возвращает указатель на этот предполагаемый D объект.
Следовательно, static_cast можно сделать обратное неявное преобразование, в этом случае результаты не определены. Программисту осталось убедиться, что результаты static_cast преобразования безопасны.
Это поведение также применяется к типам, отличным от типов класса. Например, static_cast можно использовать для преобразования из int в объект char . Однако результирующий char результат может не иметь достаточно битов для хранения всего int значения. Опять же, программисту осталось убедиться, что результаты static_cast преобразования безопасны.
Оператор static_cast также можно использовать для выполнения любого неявного преобразования, включая стандартные преобразования и определяемые пользователем преобразования. Например:
// static_cast_Operator_3.cpp // compile with: /LD /GR typedef unsigned char BYTE; void f() < char ch; int i = 65; float f = 2.5; double dbl; ch = static_cast(i); // int to char dbl = static_cast(f); // float to double i = static_cast(ch); >
Оператор static_cast может явно преобразовать целочисленное значение в тип перечисления. Если значение типа целого не оказывается в диапазоне значений перечисления, получаемое значение перечисления не определено.
Оператор static_cast преобразует значение указателя NULL в значение null указателя целевого типа.
Любое выражение можно явно преобразовать в тип void оператором static_cast . Тип конечной пустоты может дополнительно включать const volatile атрибут или __unaligned атрибут.
Оператор static_cast не может отбросить const volatile атрибуты или __unaligned атрибуты. Сведения об удалении этих атрибутов см . в const_cast операторе .
C++/CLI: из-за опасности выполнения не проверка приведения на вершине перемещенного сборщика мусора, использование static_cast должно находиться только в критическом коде производительности, если вы уверены, что он будет работать правильно. Если вы должны использовать static_cast в режиме выпуска, замените его safe_cast в сборках отладки, чтобы убедиться в успешном выполнении.
Синтаксис: приведение типов данных в C и C++
Cи-стиль приведения типов данных доступен и языке C++, но считается не самодостаточным по сравнению с приведением типов в C++. Так как Си-стиль приведения типов не так точен, как C++-стиль приведения и не так заметен. Cи-стиль приведения типов данных может быть использован для преобразования любого типа в любой другой тип, при этом неважно насколько это небезопасное преобразование, например, преобразование целого числа в указатель типа int ). Казалось бы, такое преобразование невозможно, однако компилятор с нами не согласен, но выполнит это приведение. И каков получится результат. ему совершенно не важно. Смотрим синтаксис приведения типов данных согласно Си-стилю:
(type) val
- type — тип данных к которому преобразуется значение val
причем тип данных обязательно указывается в круглых скобочках.
Рассмотрим следующий пример использования Си-стиля приведения типа данных int к типу double .
double res = (double)13 / 7;
Этот пример приводит int к типу double для того, чтобы при делении 13-ти на 7 избежать усечения результата из-за целочисленного деления. Если вы плохо знакомы с приведением типов данных, прочтите статью: Явное и неявное приведение типов данных.
static_cast — унарная операция приведения типов данных в С++
Операция static_cast доступна только в языке C++. static_cast может быть использована для преобразования одного типа в другой, но она не должна быть использована для выполнения недопустимого преобразования, например, преобразование значения в указатель или наоборот. Рекомендуется пользоваться операцией static_cast , нежели Cи-стилем приведения, потому что static_cast ограничивает недопустимое приведение типов и, следовательно — безопаснее.
Операция static_cast , грубо говоря, — это шаблон функции, в которой необходимо явно указать тип данных для преобразования, то есть задать параметр шаблона.
static_cast(value);
Итак, в треугольных скобочках указывается тип данных, к которому необходимо преобразовать значение value , которое стоит в круглых скобочках. Смотрим все тот же пример, который приводит int к типу double для того, чтобы при делении 13-ти на 7 избежать усечения результата из-за целочисленного деления.
double res = static_cast(13)/7;
dynamic_cast — унарная операция приведения типов данных в С++
Операция dynamic_cast доступна только в C++ и имеет смысл только, применительно к членам класса иерархии «полиморфных типов». Динамическое приведение типов данных может быть использовано для безопасного приведения указателя (или ссылки) на суперкласс, в указатель (или ссылку) на подкласс в иерархии классов. Если динамическое приведение типов — недопустимо, так как реальный тип объекта, указывает не на тот тип подкласса, приведение типов не выполнится.
Динамическое приведение указателя
При приведении указателя, в случае неудачи, dynamic_cast возвращает нулевой указатель NULL . Такое поведение обеспечивает быстрый способ определения, является ли данный объект частностью динамического типа.
Синтаксис указателя динамического приведения:
type *subСlass = dynamic_cast( objPtr );
Динамическое приведение ссылки
При приведении ссылочной переменной, не возможно вернуть указатель, в случае неудачи. Поэтому будет вызвано исключение std::bad_cast (из заголовочного файла ).
type subСlass = dynamic_cast( objReference );
Чтобы безопасно пользоваться динамическим приведением, все вызовы dynamic_cast должны быть обрамлены в блок Try/Catch .
const_cast — константное приведение типов данных
Операция const_cast доступна только в C++. Константное приведение используются, чтобы константную переменную преобразовать в неконстантную. При этом, константным становится возвращаемое значение операции const_cast , а не сама переменная.
const_cast(val);
Следующий пример преобразует константный указатель на символьную строку в неконстантный указатель на эту же строку.
void function(char *); // прототип функции с неконстантным параметром const char *string = "Sevastopol"; // константная строка function(const_cast(string));
reinterpret_cast — операция приведения типов данных
Операция reinterpret_cast доступна только в C++ и является наименее безопасной формой приведения типов данных в С++, она позволяет интерпретировать значение в другой тип данных. reinterpret_cast не должна быть использована для приведения иерархии классов или преобразования константных переменных.
reinterpret_cast( value );
Рассмотрим пример использования этой операции приведения, например, чтобы преобразовать целое значение в указатель, нужно написать следующее:
reinterpret_cast(777);
Более подробно о приведении типов данных читайте в статье: Явное и неявное преобразование типов данных.
Для чего нужен static_cast, как он работает и где его применяют?
У static_cast очень много различных применений. Его идея состоит в следующем: это ограниченный по мощи C-style cast. Ограничение нужно потому, что C-style cast может привести что угодно к чему угодно (ну, почти), и тем самым может скрыть ошибку. Например, вы можете случайно закастить const char* в char* , получив крэш в некоторых системах с аппаратной поддержкой const-памяти. static_cast вам такого не позволит.
Большую часть времени, когда вы хотите сделать явное преобразование типов (а я надеюсь, это бывает достаточно редко), вы хотите именно static_cast .
Формальный список всего, что умеет static_cast , очень большой, я приведу лишь наиболее важные вещи, которые он умеет (а также которые он не умеет):
- Преобразование указателя на родительский класс к указателю на дочерний класс. Объект по указателю обязан быть правильного дочернего класса, иначе undefined behaviour. Если вы не уверены и хотите проверить, тот ли подкласс у объекта, пользуйтесь dynamic_cast (он специально для этого предназначен).
- Преобразования между числовыми типами. int , long , char , unsigned int — все их можно кастить друг в друга при помощи static_cast .
- Можно закастить любое выражение в void . Результат будет вычислен и отброшен (но побочные эффекты, разумеется, выполнятся).
- static_cast может привести константу nullptr к любому типу-указателю. Обычно это не нужно и можно полагаться на неявное преобразование типов, но иногда (например, для выбора нужной перегрузки функции) такое может пригодится.
- Преобразование между указателями на в принципе несовместимые типы. Например, указатель на double нельзя привести к указателю на int . Для трюков с нарушением type safety пользуйтесь reinterpret_cast .
- Указатели на типы, а также сами типы с несовместимыми атрибутами const и/или volatile . Если вам необходимо нарушить const-корректность, пользуйтесь const_cast .
- Разумеется, вы не сможете привести указатель на функцию-член к указателю на обычную функцию, или указатель на код к указателю на данные. Для подобных грязных хаков пользуйтесь reinterpret_cast .
Ещё одной причиной использования static_cast (как и других C++-специфических преобразований типов) является лёгкость его поиска в исходниках, как глазами, так и поисковыми утилитами. Сишный каст (особенно его функциональную разновидность) очень легко пропустить в коде.
Для сравнения, «привычное» преобразование типов (C-style cast) равносильно следующей последовательности:
- const_cast .
- Если const_cast не может дать нужный результат, то static_cast (но с разрешённым преобразованием к недообъявленному типу)
- Если и так не выходит, то компилятор пробует в хвост к static_cast добавить const_cast .
- Если и это не получается, то reinterpret_cast .
- . а если не выйдет, то к нему дописывается const_cast .
Static cast int c что это
С++ является статически типизированным языком программирования. То есть если мы определили для переменной какой-то тип данных, то в последующем мы этот тип изменить не сможем. Соответственно переменная может получить значения только того типа, который она представляет. Однако нередко возникает необходимость присвоить переменной значения каких-то других типов. И в этом случае применяются преобразования типов.
Ряд преобразований компилятор может производить неявно, то есть автоматически. Например:
#include int main() < unsigned int age; std::cout #include int main() < unsigned int age; std::cout g++:error: narrowing conversion of '-25' from 'int' to 'unsigned int' [-Wnarrowing]Примеры неявных преобразований
Рассмотрим, как выполняются некоторые базовые преобразования:
-
Переменной типа bool присваивается значение другого типа. В этом случае переменная получает false , если значение равно 0. Во всех остальных случаях переменная получает true .
bool a = 1; // true bool b = 0; // false bool c = 'g'; // true bool d = 3.4; // true
int c = true; // 1 double d = false; // 0
int a = 3.4; // 3 int b = 3.6; // 3
float a = 35005; // 35005 double b = 3500500000033; // 3.5005e+012
unsigned char a = -5; // 251 unsigned short b = -3500; // 62036 unsigned int c = -50000000; // 4244967296
Преобразования в арифметических операциях
В арифметических операциях необходимо, чтобы оба операнда представляли один и тот же тип. Если же операнды имеют разные типы, то компилятор автоматически выбирает операнд с типом который имеет меньший диапазон значений и пытается его преобразовать в тип второго операнда, который имеет больший диапазон значений. С точки зрения преобразований в операциях типы можно расположить следующим образом в порядке приоритета (от более высокого к более низкому):
- long double
- double
- float
- unsigned long long
- long long
- unsigned long
- long
- unsigned int
- int
То есть, если в операции участвует число типа float и типа long double , то компилятор автоматически преобразует операнд типа float в тип long double (который в соответствии с вышеуказанным списком имеет более высокий приоритет).
Операнды типов char, signed char, unsigned char, short и unsigned short всегда при операциях преобразуются как минимум в тип int
Например, программист заработал за 8 часовой рабочий день 100,2$, рассчитаем его заработок за час:
#include int main() < double sum ; int hours ; double revenuePerHour ; std::cout double.С одной стороны, это может показаться довольно удобно. С другой стороны, подобные преобразования могут привести к нежелательным результатам. Например:
#include int main() < int n ; unsigned int x ; std::cout bool -> char -> short -> int -> double -> long doublebool -> char -> short -> int -> long -> long long
unsigned char -> unsigned short -> unsigned int -> unsigned long
float -> double -> long double
Примеры безопасных преобразований:
short a = 'g'; // преобразование из char в short int b = 10; double c = b; // преобразование из int в double float d = 3.4; double e = d; // преобразование из float в double double f = 35; // преобразование из int в doubleНо также есть опасные преобразования. При подобных преобразованиях мы потенциально можем потерять точность данных. Как правило, это преобразования от типа с большей разрядностью к типу с меньшей разрядностью.
unsigned int a = -25; // 4294967271 unsigned short b = -3500; // 62036В данном случае переменным a и b присваивается значения, которые выходят за пределы диапазона допустимых значений для данных типов.
И в подобных примерах многое зависит от компилятора. В ряде случаев компиляторы при компиляции выдают предупреждение, тем не менее программа может быть успешно скомпилирована. В других случаях компиляторы не выдают никакого предупреждения. Собственно в этом и заключается опасность, что программа успешно компилируется, но тем не менее существует риск потери точности данных. Значение переменной - это всего лишь набор битов в памяти, которые интерпретируются в соответствии с определенным типом. И для разных типов один и тот же набор битов может интерпретироваться по разному. Поэтому важно учитывать диапазоны значений для того или иного типа при присвоении переменной значения.
Если речь идет об инициализации переменных, то, чтобы избежать опасных преобразований, когда может произойти потеря точности, рекомендуется использовать инициализацию в фигурных скобках:
unsigned int a ; // ! Ошибка unsigned short b ; // ! ОшибкаВ этом случае компилятор сгенерирует ошибку, и программа не скомпилируется.
Явные преобразования типов
Для выполнения явных преобразований типов (explicit type conversion) применяется оператор static_cast
static_cast(value)Данный оператор преобразует значение в круглых скобках - value к типу, который указан в угловых скобках - type . Слово static в названии оператора отражает тот факт, что приведение проверяется статически, то есть во время компиляции.
Применение оператора static_cast указывает компилятору, что мы уверены, что в этом месте надо применить преобразование, поэтому даже при инициализации в фигурных скобках компилятор не сгенерирует ошибку. Например, программист заработал за 8 часовой рабочий день 100,2$, рассчитаем его заработок за час, но в виде значения unsigned int :
#include int main() < double sum ; unsigned int hours ; unsigned int revenuePerHour < static_cast(sum/hours) >; // revenuePerHour = 12 std::cout (тип) значениеТо есть перед преобразуемым значением в круглых скобках указывался тип, в который надо выполнить преобразование. Например, используем эту операцию в ранее приведенном коде:
#include int main() < double sum ; unsigned int hours ; unsigned int revenuePerHour < (unsigned int)sum/hours>; // revenuePerHour = 12 std::cout static_cast .