수색…
소개
어떤 캐스트 유형이 의도되었는지에 따라 dynamic_cast<T>
, static_cast<T>
, reinterpret_cast<T>
또는 const_cast<T>
사용하여 표현식을 명시 적으로 변환 하거나 유형 T
캐스트 할 수 있습니다.
C ++은 함수 스타일 캐스트 표기법, T(expr)
및 C 스타일 캐스트 표기법 (T)expr
합니다.
통사론
- 단순형 지정자
(
)
- 단순형 지정자
(
표현식 목록)
- 단순 유형 지정자 braced-init-list
- typename-specifier
(
)
- typename-specifier
(
표현식 목록)
- typename-specifier braced-init-list
-
dynamic_cast
<
type-id>
(
표현식)
-
static_cast
<
type-id>
(
표현식)
-
reinterpret_cast
<
type-id>
(
표현식)
-
const_cast
<
type-id>
(
표현식)
-
(
type-id)
캐스트 표현식
비고
여섯 가지 표기법 모두 공통점이 하나 있습니다.
-
dynamic_cast<Derived&>(base)
에서와 같이 lvalue 참조 유형으로 변환하면 lvalue가됩니다. 따라서 동일한 객체를 사용하여 다른 유형으로 처리하려는 경우에는 왼쪽 값 참조 유형으로 형변환해야합니다. -
static_cast<string&&>(s)
와 마찬가지로 rvalue 참조 유형으로 변환하면 rvalue가 반환됩니다. -
(int)x
와 같이 비표준 유형으로 변환하면 prvalue가 생성됩니다.이 값은 캐스트되는 값의 사본 으로 간주 될 수 있지만 원본과 다른 유형으로 간주 될 수 있습니다.
reinterpret_cast
키워드는 두 가지 종류의 "안전하지 않은"전환을 수행합니다.
- 한 유형의 메모리를 다른 유형 인 것처럼 액세스하는 데 사용할 수있는 "유형 punning" 변환.
- 어느 방향 으로든 정수 유형과 포인터 유형 간의 변환.
static_cast
키워드는 다양한 전환을 수행 할 수 있습니다.
파생 된 전환 수 기준
암시 적 변환과 명시 적 생성자 또는 변환 함수를 호출하는 변환을 모두 포함하여 직접 초기화로 수행 할 수있는 모든 변환. 자세한 내용은 여기 및 여기 를 참조하십시오.
void
, 식의 값을 버립니다.// on some compilers, suppresses warning about x being unused static_cast<void>(x);
산술과 열거 형 사이, 그리고 다른 열거 형 사이. enum 전환 보기
파생 클래스의 멤버에 대한 포인터에서 기본 클래스의 멤버에 대한 포인터를 가리 킵니다. 가리키는 유형이 일치해야합니다. 멤버에 대한 포인터의 파생 변환에서 기본 변환 참조
- lvalue에서 xvalue까지
std::move
. 이동 의미를 참조하십시오.
기초에서 파생 된 전환
기본 클래스에 대한 포인터는 static_cast
사용하여 파생 클래스에 대한 포인터로 변환 할 수 있습니다. static_cast
는 런타임 검사를하지 않으므로 포인터가 실제로 원하는 유형을 가리 키지 않으면 정의되지 않은 동작이 발생할 수 있습니다.
struct Base {};
struct Derived : Base {};
Derived d;
Base* p1 = &d;
Derived* p2 = p1; // error; cast required
Derived* p3 = static_cast<Derived*>(p1); // OK; p2 now points to Derived object
Base b;
Base* p4 = &b;
Derived* p5 = static_cast<Derived*>(p4); // undefined behaviour since p4 does not
// point to a Derived object
마찬가지로 기본 클래스에 대한 참조는 static_cast
사용하여 파생 클래스에 대한 참조로 변환 할 수 있습니다.
struct Base {};
struct Derived : Base {};
Derived d;
Base& r1 = d;
Derived& r2 = r1; // error; cast required
Derived& r3 = static_cast<Derived&>(r1); // OK; r3 now refers to Derived object
소스 유형이 다형성 인 경우 dynamic_cast
를 사용하여 기본에서 파생 된 변환을 수행 할 수 있습니다. 런타임 검사를 수행하고 정의되지 않은 동작을 생성하는 대신 오류를 복구 할 수 있습니다. 포인터의 경우 실패 할 때 null 포인터가 반환됩니다. 참조 경우 std::bad_cast
유형 (또는 std::bad_cast
에서 파생 된 클래스)의 실패시 예외가 발생합니다.
struct Base { virtual ~Base(); }; // Base is polymorphic
struct Derived : Base {};
Base* b1 = new Derived;
Derived* d1 = dynamic_cast<Derived*>(b1); // OK; d1 points to Derived object
Base* b2 = new Base;
Derived* d2 = dynamic_cast<Derived*>(b2); // d2 is a null pointer
멀리 던지기
const 객체에 대한 포인터는 const_cast
키워드를 사용하여 비 const 객체에 대한 포인터로 변환 될 수 있습니다. 여기에서는 const_cast
를 사용하여 const-correct가 아닌 함수를 호출합니다. 포인터를 통해 결코 쓰지는 않지만 const가 아닌 char*
인수 만 허용합니다.
void bad_strlen(char*);
const char* s = "hello, world!";
bad_strlen(s); // compile error
bad_strlen(const_cast<char*>(s)); // OK, but it's better to make bad_strlen accept const char*
const_cast
를 참조 형식으로 사용하면 const 한정 lvalue를 const가 아닌 값으로 변환 할 수 있습니다.
const_cast
는 C ++ 유형 시스템이 const 객체를 수정하지 못하도록하기 때문에 위험합니다. 그렇게하면 정의되지 않은 동작이 발생합니다.
const int x = 123;
int& mutable_x = const_cast<int&>(x);
mutable_x = 456; // may compile, but produces *undefined behavior*
펀딩 변환 입력
객체 유형에 대한 포인터 (참조 참조)는 reinterpret_cast
사용하여 다른 객체 유형에 대한 포인터 (참조 참조)로 변환 될 수 있습니다. 이것은 생성자 나 변환 함수를 호출하지 않습니다.
int x = 42;
char* p = static_cast<char*>(&x); // error: static_cast cannot perform this conversion
char* p = reinterpret_cast<char*>(&x); // OK
*p = 'z'; // maybe this modifies x (see below)
reinterpret_cast
의 결과는 주소가 대상 유형에 대해 적절히 정렬되어 있으면 피연산자와 동일한 주소를 나타냅니다. 그렇지 않으면 결과가 지정되지 않습니다.
int x = 42;
char& r = reinterpret_cast<char&>(x);
const void* px = &x;
const void* pr = &r;
assert(px == pr); // should never fire
reinterpret_cast
의 결과는 지정되지 않습니다. 단, 대상 유형의 정렬 요구 사항이 소스 유형보다 엄격하지 않은 한 포인터 (참조 참조)가 소스 유형에서 대상 유형 및 대상으로 왕복하는 동안 생존 할 수 있다는 점을 제외하고는 reinterpret_cast
의 결과는 지정되지 않습니다.
int x = 123;
unsigned int& r1 = reinterpret_cast<unsigned int&>(x);
int& r2 = reinterpret_cast<int&>(r1);
r2 = 456; // sets x to 456
대부분의 구현에서 reinterpret_cast
는 주소를 변경하지 않지만이 요구 사항은 C ++ 11까지 표준화되지 않았습니다.
reinterpret_cast
는 한 포인터에서 다른 데이터 멤버 유형으로 변환하거나 한 포인터에서 다른 멤버 함수 유형으로 변환하는 데에도 사용할 수 있습니다.
reinterpret_cast
사용하면 reinterpret_cast
를 사용하여 얻은 포인터 나 참조를 통해 읽거나 쓰는 것이 소스 유형과 대상 유형이 관련이없는 경우 정의되지 않은 동작을 트리거 할 수 있으므로 reinterpret_cast
를 사용하는 것은 위험한 것으로 간주됩니다.
포인터와 정수 사이의 변환
객체 포인터 ( void*
포함) 또는 함수 포인터는 reinterpret_cast
사용하여 정수 유형으로 변환 할 수 있습니다. 대상 유형이 충분히 긴 경우에만 컴파일됩니다. 결과는 구현에 따라 정의되며 일반적으로 포인터가 가리키는 메모리에있는 바이트의 숫자 주소를 생성합니다.
일반적으로 long
또는 unsigned long
은 포인터 값을 보유 할만큼 충분히 길지만 표준에 의해 보장되지는 않습니다.
std::intptr_t
및 std::uintptr_t
유형이있는 경우 void*
(따라서 객체 유형에 대한 포인터)를 보유 할 수있을만큼 길어질 수 있습니다. 그러나 함수 포인터를 보유 할만큼 길지는 않습니다.
마찬가지로 reinterpret_cast
를 사용하여 정수 유형을 포인터 유형으로 변환 할 수 있습니다. 다시 결과는 구현에 따라 정의되지만 포인터 값은 정수 유형을 통한 왕복 이동에 의해 변경되지 않습니다. 표준은 값 0이 널 포인터로 변환되는 것을 보증하지 않습니다.
void register_callback(void (*fp)(void*), void* arg); // probably a C API
void my_callback(void* x) {
std::cout << "the value is: " << reinterpret_cast<long>(x); // will probably compile
}
long x;
std::cin >> x;
register_callback(my_callback,
reinterpret_cast<void*>(x)); // hopefully this doesn't lose information...
명시 적 생성자 또는 명시 적 변환 함수로 변환
명시 적 생성자 또는 변환 함수를 호출하는 변환은 암시 적으로 수행 될 수 없습니다. static_cast
사용하여 명시 적으로 변환을 요청할 수 있습니다. 결과는 임시 결과 인 경우를 제외하고 직접 초기화의 의미와 같습니다.
class C {
std::unique_ptr<int> p;
public:
explicit C(int* p) : p(p) {}
};
void f(C c);
void g(int* p) {
f(p); // error: C::C(int*) is explicit
f(static_cast<C>(p)); // ok
f(C(p)); // equivalent to previous line
C c(p); f(c); // error: C is not copyable
}
암시 적 변환
static_cast
는 암시 적 변환을 수행 할 수 있습니다. static_cast
를 다음과 같이 유용하게 사용할 수 있습니다.
인수를 줄임표로 전달할 때 "예상 된"인수 유형은 정적으로 알려지지 않으므로 암시 적 변환이 발생하지 않습니다.
const double x = 3.14; printf("%d\n", static_cast<int>(x)); // prints 3 // printf("%d\n", x); // undefined behaviour; printf is expecting an int here // alternative: // const int y = x; printf("%d\n", y);
명시 적 유형 변환이 없으면,
double
오브젝트가 생략 부호로 전달되고 정의되지 않은 동작이 발생합니다.파생 클래스 할당 연산자는 다음과 같이 기본 클래스 할당 연산자를 호출 할 수 있습니다.
struct Base { /* ... */ }; struct Derived : Base { Derived& operator=(const Derived& other) { static_cast<Base&>(*this) = other; // alternative: // Base& this_base_ref = *this; this_base_ref = other; } };
전환 수 계산
static_cast
는 정수 또는 부동 소수점 유형을 열거 형 또는 범위를 벗어난 열거 형으로 변환 할 수 있으며 반대의 경우도 마찬가지입니다. 열거 형간에 변환 할 수도 있습니다.
- 범위가 지정되지 않은 열거 유형에서 산술 유형으로의 변환은 암시 적 변환입니다.
static_cast
를 사용하는 것은 가능하지만 반드시 필요한 것은 아닙니다.
범위가 지정된 열거 유형이 산술 유형으로 변환되는 경우 :
- 열거 형의 값을 대상 유형에서 정확하게 표현할 수 있으면 결과는 해당 값입니다.
- 그렇지 않으면 대상 유형이 정수 유형이면 결과가 지정되지 않습니다.
- 그렇지 않은 경우 대상 유형이 부동 소수점 유형 인 경우 결과는 기본 유형으로 변환 한 다음 부동 소수점 유형으로 변환 할 때와 동일합니다.
예:
enum class Format { TEXT = 0, PDF = 1000, OTHER = 2000, }; Format f = Format::PDF; int a = f; // error int b = static_cast<int>(f); // ok; b is 1000 char c = static_cast<char>(f); // unspecified, if 1000 doesn't fit into char double d = static_cast<double>(f); // d is 1000.0... probably
정수 또는 열거 형을 열거 형으로 변환 할 때 :
- 원래 값이 대상 열거 형 범위 내에 있으면 결과는 해당 값입니다. 이 값은 모든 열거 자와 같지 않을 수 있습니다.
- 그렇지 않으면 결과가 지정되지 않거나 (<= C ++ 14) 또는 정의되지 않습니다 (> = C ++ 17).
예:
enum Scale { SINGLE = 1, DOUBLE = 2, QUAD = 4 }; Scale s1 = 1; // error Scale s2 = static_cast<Scale>(2); // s2 is DOUBLE Scale s3 = static_cast<Scale>(3); // s3 has value 3, and is not equal to any enumerator Scale s9 = static_cast<Scale>(9); // unspecified value in C++14; UB in C++17
부동 소수점 형이 열거 형으로 변환되면 결과는 열거 형의 기본 형식으로 변환 된 다음 열거 형으로 변환됩니다.
enum Direction { UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3, }; Direction d = static_cast<Direction>(3.14); // d is RIGHT
멤버에 대한 포인터에 대한 기본 변환으로 파생되었습니다.
파생 클래스의 멤버에 대한 포인터는 static_cast
사용하여 기본 클래스의 멤버에 대한 포인터로 변환 할 수 있습니다. 가리키는 유형이 일치해야합니다.
피연산자가 멤버 값에 대한 널 포인터 인 경우, 결과는 멤버 값에 대한 널 포인터이기도합니다.
그렇지 않으면 피연산자가 가리키는 멤버가 대상 클래스에 실제로 존재하거나 대상 클래스가 피연산자가 가리키는 멤버를 포함하는 클래스의 기본 클래스 또는 파생 클래스 인 경우에만 변환이 유효합니다. static_cast
는 유효성을 검사하지 않습니다. 변환이 유효하지 않은 경우 동작은 정의되지 않습니다.
struct A {};
struct B { int x; };
struct C : A, B { int y; double z; };
int B::*p1 = &B::x;
int C::*p2 = p1; // ok; implicit conversion
int B::*p3 = p2; // error
int B::*p4 = static_cast<int B::*>(p2); // ok; p4 is equal to p1
int A::*p5 = static_cast<int A::*>(p2); // undefined; p2 points to x, which is a member
// of the unrelated class B
double C::*p6 = &C::z;
double A::*p7 = static_cast<double A::*>(p6); // ok, even though A doesn't contain z
int A::*p8 = static_cast<int A::*>(p6); // error: types don't match
void *에서 T *
C ++에서 void*
는 암시 적으로 T*
로 변환 될 수 없습니다. 여기서 T
는 객체 유형입니다. 대신 static_cast
를 사용하여 명시 적으로 변환을 수행해야합니다. 피연산자가 실제로 T
객체를 가리키는 경우 결과는 해당 객체를 가리 킵니다. 그렇지 않으면 결과가 지정되지 않습니다.
피연산자가 T
객체를 가리 키지 않더라도 피연산자가 유형 T
대해 주소가 올바르게 정렬 된 바이트를 가리키는 한 변환 결과는 같은 바이트를 가리 킵니다.
// allocating an array of 100 ints, the hard way
int* a = malloc(100*sizeof(*a)); // error; malloc returns void*
int* a = static_cast<int*>(malloc(100*sizeof(*a))); // ok
// int* a = new int[100]; // no cast needed
// std::vector<int> a(100); // better
const char c = '!';
const void* p1 = &c;
const char* p2 = p1; // error
const char* p3 = static_cast<const char*>(p1); // ok; p3 points to c
const int* p4 = static_cast<const int*>(p1); // unspecified in C++03;
// possibly unspecified in C++11 if
// alignof(int) > alignof(char)
char* p5 = static_cast<char*>(p1); // error: casting away constness
C 스타일의 주조
C-Style 캐스팅은 'Best effort'캐스팅으로 간주 될 수 있으며 C에서 사용할 수있는 유일한 캐스팅으로 명명됩니다.이 캐스트의 구문은 (NewType)variable
입니다.
이 캐스트가 사용될 때마다 다음 C ++ 캐스트 중 하나를 사용합니다 (순서대로).
-
const_cast<NewType>(variable)
-
static_cast<NewType>(variable)
-
const_cast<NewType>(static_cast<const NewType>(variable))
-
reinterpret_cast<const NewType>(variable)
-
const_cast<NewType>(reinterpret_cast<const NewType>(variable))
함수 형 변환은 구문의 결과로 몇 가지 제한 사항이 있지만 NewType(expression)
과 매우 유사합니다. 결과적으로 공백이없는 유형 만 캐스팅 할 수 있습니다.
더 읽기 쉽고 C ++ 소스 코드 내부 어디에서나 쉽게 발견 할 수 있고 런타임에 대신 컴파일 타임에 오류가 감지되므로 새로운 C ++ 캐스트를 사용하는 것이 좋습니다.
이 캐스트는 의도하지 않은 reinterpret_cast
초래할 수 있으므로 종종 위험한 것으로 간주됩니다.