Programming/C,C++

[C,C++] Inheritance and Type Casting

충남대이적 2025. 10. 10. 23:24

Type Casting

Upcasting & Downcasting

이해를 돕기위해 아래와 같은 클래스가 있다고 하자.

#include <iostream>

class Car
{
public:
    Car(std::string name) : name_(name) {}
    const std::string &name() const { return name_; }

private:
    std::string name_;
};

class Bus : public Car
{
public:
    Bus(std::string name) : Car(name), money_(0), bus_name_("BBus") {}
    void GetCharge(int charge) { money_ += charge; }
    int money() { return money_; }
    const std::string &name() const { return bus_name_; }

private:
    int money_;
    const std::string bus_name_;
};

 

Car는 Bus일 수 있지만, Bus는 Car일 수 없기때문에 마지막 경우는 컴파일에러가 발생한다.

Car *car = new Car("myCar");
Bus *bus = new Bus("myBus");
Car *car_bus = new Bus("car_bus");
Bus *bus_car = new Car("bus_car"); # ERROR

 

 

아래 코드에서 bus를 사용해서 멤버함수를 호출하면 Car클래스에 동일한 멤버함수가 정의되어있더라도 Bus클래스의 멤버함수가 호출된다. car를 사용해서 멤버함수를 호출하면 Car의 멤버함수가 호출된다. car_bus를 사용해서 멤버함수를 호출하면 Bus객체가 들어있음에도 Car 멤버함수가 호출된다. 그리고 car_bus를 사용해서 Bus의 멤버함수에 접근할 수 없다.
위의 것들을 이해하기 위해서는 static dispatch와 dynamic dispatch를 이해해야한다.

int main()
{
    Car *car = new Car("myCar");
    Bus *bus = new Bus("myBus");
    Car *car_bus = new Bus("car_bus");
    std::cout << car->name() << std::endl;     // myCar
    std::cout << bus->name() << std::endl;     // BBus
    std::cout << car_bus->name() << std::endl; // car_bus

    car->money() // ERROR

    return 1;
}

 

Static dispatch vs Dynamic dispatch

이 개념 별거없다.

static dispatch는 컴파일러가 어떤 함수를 호출해야하는지를 컴파일 타임에 정해놓는 것이고,

dynamic dispatch는 컴파일러가 어떤 함수를 호출해야하는지를 런타임에 결정하는 것이다.

C++는 기본적으로 static dispatch를 사용한다. 그러니 변수타입을 보고 어떤 함수를 호출할지를 정하는거라서 위와 같은 현상들이 나타나는 것이다.

static_cast

class hierarchy를 사용해서 type compatibility를 검사한다.

하지만 static_cast는 완벽하게 검사해주지는 못한다.

예를 들어, 아래와 같은 class hierarchy가 있다고 생각해보자.

 

Bus객체를 ConvertibleCar 객체로 변환하는 것은 static cast로 방지할 수 있지만, bus_car와 같이 Car*안에 Bus가 들어있으면 변환을 해버린다.

int main() {
    Car* bus_car = new Bus("myBus");

    Bus* bus = static_cast<Bus*>(bus_car);  // OK: Car* -> Bus*
    ConvertibleCar* conv_car = static_cast<ConvertibleCar*>(bus_car);  // OK: Z4ConvertibleCar* -> ConvertibleCar*
    Z4ConvertibleCar* z4_conv_car = static_cast<Z4ConvertibleCar*>(bus_car);  // OK: Car* -> Z4ConvertibleCar*

    ConvertibleCar* conv_bus = static_cast<ConvertibleCar*>(bus);  // Not allowed: Bus* -> ConvertibleCar*
    Z4ConvertibleCar* z4_conv_bus = static_cast<Z4ConvertibleCar*>(bus);  // Not allows: Bus* -> Z4ConvertibleCar*
    return 1;
}

 

dynamic_cast

RTTI(RunTime Type Information)을 사용해 type compatibility를 검사한다.

casting이 안되면 nullptr을 반환하고, 가능하면 변환된 값을 반환한다.

reinterpret_cast

비트 단위로 타입을 강제로 재해석할 때 사용한다 (메모리 구조를 그대로 두고 다른 타입으로 본다).

const_cast

객체의 const나 volatile 속성을 제거하거나 추가할 때 사용한다.

'Programming > C,C++' 카테고리의 다른 글

[C, C++] Make  (1) 2025.10.10
오버라이딩을 통한 다형성의 실현(virtual 개념, 오버라이딩 개념)  (0) 2022.03.01
참조리턴  (0) 2022.02.23
복사생성자  (0) 2022.02.23
연산자 중복  (0) 2022.02.22