Dev

C++ 이야기 - [3] 캐스트 연산자 static_cast

prostars 2007. 10. 14. 18:40
C++의 4가지 캐스트 연산자에 대한 이야기 중 세 번째다.
이번은 그중에서 static_cast 에 대해서 이야기한다.

static_cast 는 기본적으로 C 스타일의 캐스팅과 가장 비슷한 기능을 한다.
물론 C 스타일의 캐스팅처럼 만능은 아니다. 4가지의 캐스트 연산자로 분리된 만큼 const_cast의 역할인 상수성을 날린다거나 하는 등의 다른 캐스트 연산자의 고유 기능은 수행하지 못한다.
다른 캐스트 연산자와 같이 static_cast 도 static_cast 만의 용도가 있다.

- static_cast 사용
static_cast 를 사용하기 전에 용도와 제약 사항을 확인하자.
  • 실수형과 정수형, 정수형과 열거형등의 기본 데이터 타입 간의 변환
  • 상속관계의 클래스 계층 간의 변환
    • 런타임 타입 검사를 하지 않음
    • 다형성이 없어도 변환 가능 (RTTI 옵션이 꺼져있어도 된다)
    • 다중 상속에서 기본 클래스 간의 타입 변환은 못함
  • void 포인터를 다른 타입의 포인터로 변환
  • 서로 다른 타입의 포인터 간의 타입 변환은 못함
서로 다른 타입의 포인터 간의 타입 변환에 reinterpret_cast 를 사용하기보다는 void 포인터를 경유하는 방식을 추천한다.

[예제 1]
class BaseOne
{
public :
    virtual void Put( void ) { cout << "BaseOne" << endl; }
};

class BaseTwo
{
public :
    virtual void Put( void ) { cout << "BaseTwo" << endl; }
};

class Derived : public BaseOne, public BaseTwo
{
public :
    void Put( void ) { cout << "Derived" << endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    int IntValue = 0;
    double DoubleValue = 100.0;

    // 암시적 캐스팅 : 경고 발생
    IntValue = DoubleValue;
    // 명시적 캐스팅 : 경고 없음
    IntValue = static_cast<int>( DoubleValue );

    // 컴파일 오류 : 변환할 수 없는 타입
    //char* pChar = static_cast<char*>( &IntValue );

    // 컴파일 성공 : void 포인터에서 변환은 가능
    void* pVoid = &IntValue;
    char* pChar = static_cast<char*>( pVoid );

    BaseOne* pBaseOne = NULL;
    BaseTwo* pBaseTwo = new Derived;
    Derived*    pDerived = NULL;

    // 컴파일 성공 : 계층간 타입 변환이 가능 (타입 안전 검사는 안함)
    pDerived = static_cast<Derived*>( pBaseTwo );

    // 컴파일 오류 : 변환할 수 없는 타입 (dynamic_cast 필요)
    //pBaseOne = static_cast<BaseOne*>( pBaseTwo );   

    return 0;
}
위의 [예제 1] 에서 static_cast 의 기본 동작을 볼 수 있다.
[예제 1] 의 'pDerived = static_cast<Derived*>( pBaseTwo );' 에서 타입 변환은 컴파일 타임에 끝난다.
pBaseTwo 에 NULL 이 들어가 있어도 컴파일은 성공한다.
즉, 변환하려는 포인터가 계층 관계에 있다면 어떤 값을 가지고 있던지 컴파일은 성공한다는 말이다.
문제는 런타임에 발생할 것이고 대부분 프로그램의 다운으로 이어질 것이다.
이런 문제점 때문에 클래스 계층 간의 타입 변환에 dynamic_cast 를 추천하는 것이다.

[예제 1] 에는 재미있는 내용이 하나 있다.
서로 다른 타입의 포인터 간의 변환은 금지지만 void 포인터를 경유한다면 가능하다.
'char* pChar = static_cast<char*>( &IntValue );' 이것은 컴파일이 안되지만,
'void* pVoid = &IntValue;
 char* pChar = static_cast<char*>( pVoid );' 이것은 컴파일이 된다. 물론 포인터 값도 정상적으로 넘어온다.
반응형