Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ static_cast와 dynamic_cast 완벽 정리: 차이점과 사용법

C++에는 네 가지 캐스트 연산자(static_cast, dynamic_cast, const_cast, reinterpret_cast)가 있으며, 그중 static_castdynamic_cast가 가장 자주 사용됩니다. 두 연산자는 모두 타입 변환을 수행하지만 검사 시점과 용도가 다르므로, 상황에 맞게 올바르게 선택하는 것이 중요합니다.


static_cast: 일반적인 타입 변환에 사용되는 캐스트입니다. 컴파일러가 수행하는 암시적 형변환(implicit type coercion)과 동일한 규칙으로 동작하며, 필요에 따라 명시적으로도 사용할 수 있습니다. float를 int로 변환하거나 char를 int로 변환하는 것처럼 서로 관련 있는 기본 타입 간의 변환에 적합합니다. 또한 상속 관계에 있는 클래스 간의 캐스팅도 가능하지만, 서로 호환되지 않는 타입으로 변환을 시도하면 컴파일 시점에 에러가 발생합니다.

예제

#include<iostream>
using namespace std;
class Base {};
class Derived : public Base {};
class MyClass {};
main(){
    Derived* d = new Derived;
    Base* b = static_cast<Base*>(d); // 이 줄은 정상적으로 동작합니다
    MyClass* x = static_cast<MyClass*>(d); // 컴파일 시점에 ERROR 발생
}

출력 결과

[Error] invalid static_cast from type 'Derived*' to type 'MyClass*'

dynamic_cast: 다형성(polymorphism)을 다룰 때 사용하는 캐스트입니다. 이 캐스트는 꼭 필요한 경우, 즉 파생 클래스(derived class)로 캐스팅할 때만 사용하면 됩니다. 주로 상속 구조에서 기본 클래스(base class) 포인터를 파생 클래스 포인터로 안전하게 변환하는 다운캐스팅(downcasting)에 활용됩니다. dynamic_cast는 런타임에 객체의 실제 타입을 검사(RTTI)하므로, 포인터 캐스팅에 실패하면 null을 반환하기 때문에 실패 여부를 안전하게 확인할 수 있다는 큰 장점이 있습니다.

예제

#include<iostream>
using namespace std;
class MyClass1 {
    public:
        virtual void print()const {
            cout << "This is from MyClass1\n";
        }
};
class MyClass2 {
    public:
        virtual void print()const {
            cout << "This is from MyClass2\n";
        }
};
class MyClass3: public MyClass1, public MyClass2 {
    public:
        void print()const {
            cout << "This is from MyClass3\n";
        }
};
int main(){
    MyClass1* a = new MyClass1;
    MyClass2* b = new MyClass2;
    MyClass3* c = new MyClass3;
    a -> print();
    b -> print();
    c -> print();
    b = dynamic_cast< MyClass2*>(a); // 이 캐스트는 실패합니다
    if (b)
        b->print();
    else
        cout << "no MyClass2\n";
    a = c;
    a -> print(); // MyClass3에서 출력됩니다
    b = dynamic_cast< MyClass2*>(a); // 성공적으로 캐스팅됩니다
    if (b)
        b -> print();
    else
        cout << "no MyClass2\n";
}

출력 결과

This is from MyClass1
This is from MyClass2
This is from MyClass3
no MyClass2
This is from MyClass3
This is from MyClass3

두 캐스트의 핵심 차이 정리

구분static_castdynamic_cast
타입 검사 시점컴파일 시간런타임
주요 용도기본 타입 간 변환, 상속 관계 캐스팅다형성 기반 안전한 다운캐스팅
타입 안전성호환 타입만 허용, 별도 검사 없음RTTI 기반 런타임 타입 검사
실패 시 동작컴파일 에러 또는 정의되지 않은 동작null 반환(포인터), bad_cast 예외(참조)
성능런타임 오버헤드 없음타입 검사 비용 발생

결론적으로, 단순한 타입 변환이나 확실한 상속 관계의 업캐스팅에는 static_cast를, 런타임에 객체의 실제 타입을 확인하면서 안전하게 다운캐스팅해야 하는 다형성 환경에서는 dynamic_cast를 사용하는 것이 바람직합니다.