Language/C++

📌 Chapter 14 - 형변환 연산자 (C++ Casting Operators)

e-cko 2025. 10. 30. 20:42
반응형

C++에서는 C 언어에서 사용하던 전통적인 형변환 방식((자료형))도 여전히 지원한다. 그러나 C 스타일 형변환은 너무 포괄적이고, 안전성이 떨어진다는 단점이 있다.

, 맞는 변환인지 아닌지를 컴파일러가 제대로 검사하지 못한다는 것이다.

예를 들어, int* 같은 포인터를 float 같은 기본형으로도 바꿀 수 있으며, 이 경우 프로그램의 안정성은 전적으로 프로그래머의 책임이다.

이를 보완하기 위해 C++에서는 4가지 형변환 연산자를 제공한다:

  • reinterpret_cast
  • const_cast
  • static_cast
  • dynamic_cast

아래에서 각각의 특징과 사용법을 살펴본다.


1. C 스타일 형변환의 한계

  1. C 스타일 형변환
    · (
    자료형)값 형태를 사용한다.
    ·
    컴파일러는 변환이 합법적인지 여부를 검사하지 않는다.
    ·
    상위 클래스와 하위 클래스 간의 잘못된 변환도 그대로 통과된다.

💻 예제 코드

#include <iostream>

using namespace std;

 

class Ex {

public:

    Ex() { cout << "Ex 생성자" << endl; }

};

 

class cEx : public Ex {

public:

    cEx() { cout << "cEx 생성자" << endl; }

};

 

int main() {

    Ex* ex = new cEx();         // 업캐스팅 (안전)

    cEx* cex1 = (cEx*)ex;       // 다운캐스팅 (위험 가능)

 

    Ex* ex2 = new Ex();

    cEx* cex2 = (cEx*)ex2;      // 잘못된 다운캐스팅 (컴파일러는 오류를 잡아내지 못함)

 

    return 0;

}

📌 위 코드에서 cex2는 실제로 Ex 객체를 가리키고 있지만, 강제로 cEx*로 변환하였다. 이는 정의되지 않은 동작(UB, Undefined Behavior)을 초래한다.

따라서, C++에서는 목적에 맞는 형변환 연산자를 사용하는 것이 안전하다.


2. reinterpret_cast

· 전혀 상관없는 자료형으로의 형변환에 사용한다.
·
포인터, 정수, 참조 등과 관련된 모든 변환을 허용한다.
·
성공 여부는 컴파일러가 보장하지 않는다. 책임은 프로그래머에게 있다.

사용법
· reinterpret_cast<T>(
대상)

💻 예제 코드

#include <iostream>

using namespace std;

 

int main() {

    int num = 65;

    char* ch = reinterpret_cast<char*>(&num); // int* → char*

    cout << "첫 번째 바이트 값: " << *ch << endl;

 

    void* ptr = &num;

    int* intPtr = reinterpret_cast<int*>(ptr); // void* → int*

    cout << "재해석된 값: " << *intPtr << endl;

 

    return 0;

}

📌 위 예시는 정상적인 reinterpret_cast 사용이다.

그러나 전혀 무관한 객체 포인터끼리 변환하면 프로그램 오류가 발생할 수 있다.


3. const_cast
· const
성질을 제거할 때 사용한다.
· const
키워드를 강제로 무시할 수 있다.

사용법
· const_cast<T>(
대상)

💻 예제 코드

#include <iostream>

using namespace std;

 

void showStr(char* str) {

    cout << str << endl;

}

 

int main() {

    const char* str = "C++ 배우기";

    showStr(const_cast<char*>(str)); // const 제거 후 전달

    return 0;

}

⚠️ 주의: 원래 const로 선언된 값을 수정하려 하면 정의되지 않은 동작이 발생한다.

따라서 const_cast는 읽기 전용 데이터를 수정하는 용도로 사용하면 안 된다.


4. static_cast
·
상속 관계에서의 업캐스팅, 다운캐스팅에 사용한다.
·
기본 자료형 간의 변환에도 사용한다.
·
잘못된 형변환을 해도 컴파일러가 에러를 잡지 못하므로 프로그래머의 주의가 필요하다.

사용법
· static_cast<T>(
대상)

💻 예제 코드

#include <iostream>

using namespace std;

 

class Ex {

public:

    virtual void show() { cout << "Ex 클래스" << endl; }

};

 

class cEx : public Ex {

public:

    void show() override { cout << "cEx 클래스" << endl; }

};

 

int main() {

    Ex* ex = new cEx();        

    cEx* cex = static_cast<cEx*>(ex); // 다운캐스팅 (위험 가능, 책임은 프로그래머)

    cex->show();

 

    float result = static_cast<float>(10) / 3; // 기본형 변환

    cout << "나눗셈 결과: " << result << endl;

 

    return 0;

}


5. dynamic_cast
·
상속 관계에서 안전한 형변환을 수행한다.
·
다운 캐스팅은 가상 함수(virtual function)가 있는 클래스에서만 동작한다. (Polymorphic Class)
·
업캐스팅은 항상 허용되며, 다운캐스팅은 유효성 검사를 거쳐 안전하게 수행된다.
·
잘못된 변환은 nullptr(포인터 변환 시) 또는 bad_cast 예외(참조 변환 시)를 발생시킨다.

사용법
· dynamic_cast<T>(
대상)

💻 예제 코드

#include <iostream>

using namespace std;

 

class Ex {

public:

    virtual void show() { cout << "Ex 클래스" << endl; } // 가상 함수

};

 

class cEx : public Ex {

public:

    void show() override { cout << "cEx 클래스" << endl; }

};

 

int main() {

    Ex* ex1 = new cEx();

    cEx* cex1 = dynamic_cast<cEx*>(ex1); // 안전한 다운캐스팅

    if (cex1) cex1->show();

 

    Ex* ex2 = new Ex();

    cEx* cex2 = dynamic_cast<cEx*>(ex2); // 실패 → nullptr 반환

    if (!cex2) cout << "변환 실패 (nullptr 반환)" << endl;

 

    return 0;

}


마무리 정리

1️ C 스타일 형변환은 안전하지 않고, 책임은 전적으로 프로그래머에게 있다.
2️
reinterpret_cast는 포인터/정수 재해석 시 사용하며 안전성은 보장되지 않는다.
3️
const_cast const 속성을 제거한다. 잘못 사용하면 UB 발생 가능하다.
4️
static_cast는 상속 관계나 기본형 변환에 사용되며, 책임은 프로그래머에게 있다.
5️
dynamic_cast는 가상 함수가 있는 상속 관계에서만 안전하게 다운캐스팅을 수행한다. 실패 시 nullptr 또는 bad_cast 예외가 발생한다.

반응형

반응형