수색…


소개

어떤 캐스트 유형이 의도되었는지에 따라 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 키워드는 두 가지 종류의 "안전하지 않은"전환을 수행합니다.

static_cast 키워드는 다양한 전환을 수행 할 수 있습니다.

  • 파생 된 전환 수 기준

  • 암시 적 변환과 명시 적 생성자 또는 변환 함수를 호출하는 변환을 모두 포함하여 직접 초기화로 수행 할 수있는 모든 변환. 자세한 내용은 여기여기 를 참조하십시오.

  • void , 식의 값을 버립니다.

    // on some compilers, suppresses warning about x being unused
    static_cast<void>(x);
    
  • 산술과 열거 형 사이, 그리고 다른 열거 형 사이. enum 전환 보기

  • 파생 클래스의 멤버에 대한 포인터에서 기본 클래스의 멤버에 대한 포인터를 가리 킵니다. 가리키는 유형이 일치해야합니다. 멤버에 대한 포인터의 파생 변환에서 기본 변환 참조

  • void* ~ T* .

C ++ 11

기초에서 파생 된 전환

기본 클래스에 대한 포인터는 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)
C ++ 11

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
C ++ 11

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 은 포인터 값을 보유 할만큼 충분히 길지만 표준에 의해 보장되지는 않습니다.

C ++ 11

std::intptr_tstd::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 를 사용하는 것은 가능하지만 반드시 필요한 것은 아닙니다.
C ++ 11
  • 범위가 지정된 열거 유형이 산술 유형으로 변환되는 경우 :

    • 열거 형의 값을 대상 유형에서 정확하게 표현할 수 있으면 결과는 해당 값입니다.
    • 그렇지 않으면 대상 유형이 정수 유형이면 결과가 지정되지 않습니다.
    • 그렇지 않은 경우 대상 유형이 부동 소수점 유형 인 경우 결과는 기본 유형으로 변환 한 다음 부동 소수점 유형으로 변환 할 때와 동일합니다.

    예:

    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
    
C ++ 11
  • 부동 소수점 형이 열거 형으로 변환되면 결과는 열거 형의 기본 형식으로 변환 된 다음 열거 형으로 변환됩니다.

    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 객체를 가리키는 경우 결과는 해당 객체를 가리 킵니다. 그렇지 않으면 결과가 지정되지 않습니다.

C ++ 11

피연산자가 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 초래할 수 있으므로 종종 위험한 것으로 간주됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow