전체 코드


1. C++ 캐스팅 종류 개요

캐스팅 연산자사용 목적특징주요 예제
static_cast기본 자료형 변환, 업/다운 캐스팅컴파일 타임에 타입 변환, 안전한 변환만 허용float -> int, Player* -> Knight*
dynamic_cast상속 관계에서의 안전한 다운 캐스팅런타임에 타입 검사, 실패 시 nullptr 반환Player* -> Knight* (RTTI 필요)
const_castconst 속성 제거 또는 추가const 속성을 변경하는 유일한 캐스팅const char* -> char*
reinterpret_cast메모리 주소 변환위험한 변환 허용 (임의의 형변환 가능)int* -> char*, void* -> Object*

2. 코드 분석

#include <iostream>
using namespace std;

// 1) 상속 관계에서 업캐스팅/다운캐스팅 실습을 위한 클래스
class Player {
public:
    virtual ~Player() {}  // RTTI를 위한 가상 소멸자
};

class Knight : public Player {
public:
    void Attack() { cout << "Knight Attack!" << endl; }
};

class Archer : public Player {
public:
    void Shoot() { cout << "Archer Shoot!" << endl; }
};

class Dog {};  // Player와 상속 관계가 없는 독립적인 클래스

// 2) const_cast 실습을 위한 함수
void PrintName(char* str) {
    cout << str << endl;
}

int main() {
    // [1] static_cast : 상식적인 타입 변환 (컴파일 타임에 검증됨)
    
    int hp = 100;
    int maxHp = 200;
    
    // 정수 나눗셈이므로, 100 / 200 = 0 (부동소수점 변환 필요)
    float ratio = static_cast<float>(hp) / maxHp;  
    cout << "ratio: " << ratio << endl;  // 0.5 출력
    
    // 업 캐스팅 (자식 -> 부모) : 컴파일러가 자동으로 변환해줌
    Knight* k = new Knight();
    Player* p1 = static_cast<Player*>(k);
    
    // 다운 캐스팅 (부모 -> 자식) : 안전성이 보장되지 않음
    Player* p2 = new Knight();  
    Knight* k1 = static_cast<Knight*>(p2);  // 가능하지만 위험할 수 있음

    // 잘못된 다운 캐스팅 (런타임 오류 가능)
    Player* p3 = new Archer();
    Knight* k2 = static_cast<Knight*>(p3);  // 논리적으로 잘못된 변환 (위험!)

    cout << "------------------------------------" << endl;

    // [2] dynamic_cast : 상속 관계에서 안전한 다운 캐스팅
    // - 가상 함수 테이블(vftable)을 활용한 런타임 타입 체크
    
    Player* p4 = new Knight();
    Knight* k3 = dynamic_cast<Knight*>(p4);  // 성공 (p4는 Knight 객체)
    
    if (k3) k3->Attack();  // 정상 출력: "Knight Attack!"

    Player* p5 = new Archer();
    Knight* k4 = dynamic_cast<Knight*>(p5);  // 실패 (nullptr 반환)

    if (!k4) cout << "p5는 Knight가 아닙니다!" << endl;  // 안전하게 확인 가능

    cout << "------------------------------------" << endl;

    // [3] const_cast : const 제거 (const 데이터를 수정해야 하는 경우 사용)
    
    const char* name = "Hello, World!";
    PrintName(const_cast<char*>(name));  // const 속성 제거 후 전달

    cout << "------------------------------------" << endl;

    // [4] reinterpret_cast : 메모리 주소 변환 (위험한 변환 가능)
    
    __int64 address = reinterpret_cast<__int64>(k3);  
    cout << "Knight 객체의 주소: " << address << endl;
    
    // 완전히 다른 클래스 간 변환 (위험!)
    Dog* dog1 = reinterpret_cast<Dog*>(k3);
    
    // malloc으로 할당한 메모리를 특정 객체로 변환 (주의 필요)
    void* p6 = malloc(1000);
    Dog* dog2 = reinterpret_cast<Dog*>(p6);

    free(p6);  // 동적 할당된 메모리 해제

    return 0;
}

3. 실행 결과 분석

ratio: 0.5
------------------------------------
Knight Attack!
p5는 Knight가 아닙니다!
------------------------------------
Hello, World!
------------------------------------
Knight 객체의 주소: 129673600

4. 캐스팅 연산자

(1) static_cast

컴파일 타임에 타입 변환이 수행됨
기본 자료형 변환 (int -> float)
업캐스팅(자식 -> 부모) 가능
다운캐스팅(부모 -> 자식) 가능하지만 안전성 보장 X
논리적으로 변환 가능하지만, 런타임 문제 발생 가능

Knight* k = new Knight();
Player* p1 = static_cast<Player*>(k);  // 업캐스팅 (안전)
Knight* k1 = static_cast<Knight*>(p1); // 다운캐스팅 (위험!)

🚨 주의:

  • static_cast는 논리적으로 변환 가능하다고 판단되면 허용하지만, 실제로 잘못된 변환이라도 오류 없이 실행될 수 있다.
  • dynamic_cast를 사용하면 잘못된 변환 시 nullptr을 반환하여 안전성을 확보할 수 있다.

(2) dynamic_cast

상속 관계에서 부모 -> 자식 변환 시 안전한 다운 캐스팅
런타임 타입 체크 (RTTI) 필요 → 실패 시 nullptr 반환
가상 함수가 있어야 사용할 수 있음 (가상 함수 테이블 활용)

Player* p = new Archer();
Knight* k = dynamic_cast<Knight*>(p);  // 실패 시 nullptr 반환

if (!k) {
    cout << "p는 Knight가 아닙니다!" << endl;
}

🚨 주의:

  • dynamic_cast가상 함수가 하나 이상 있는 클래스에서만 사용 가능
  • 잘못된 변환을 방지하기 위해 사용되지만, 성능이 떨어질 수 있음

(3) const_cast

const 속성을 제거하거나 추가하는 데 사용
함수의 매개변수 타입을 변경할 때 유용
실제 값을 변경하려 하면 "정의되지 않은 동작" 발생 가능

const char* name = "Hello";
PrintName(const_cast<char*>(name));  // const 제거

🚨 주의:

  • const_cast를 사용하여 상수를 변경하면 프로그램이 크래시할 가능성이 있음.

(4) reinterpret_cast

완전히 다른 타입 간 변환 가능 (위험한 변환 허용)
포인터 → 정수, 정수 → 포인터 변환 가능
일반적으로 메모리 주소를 다룰 때 사용됨

Knight* k = new Knight();
__int64 address = reinterpret_cast<__int64>(k);
cout << "Knight 주소: " << address << endl;

🚨 주의:

  • 완전히 다른 타입 간 변환도 허용하지만, 오류 발생 가능성이 높음
  • 가급적 사용을 피해야 하며, 반드시 필요할 때만 신중하게 사용해야 함

profile
李家네_공부방

0개의 댓글