본문 바로가기
카테고리 없음

[C++] Upcasting

by 까망 하르방 2025. 2. 22.
반응형

Upcasting

기반 클래스 포인터로 파생 클래스 객체를 가리킬 수 있다.

기반 클래스 포인터로는 기반 클래스 멤버만 접근 가능

• 파생 클래스 접근하려면 static_cast 필요

 

[예제] upcasting 이란

class Animal
{
public:
    int age;
};

class Cat : public Animal
{
public:
    int leg;
};

int main()
{
    Cat c;
    Cat*    p1 = &c; // ok
    Animal* p2 = &c; // ok (upcasting)

    p2->age = 5; // ok
}

 

Animal* p2 는 기반 클래스 age 변수에만 접근 가능하다.

그렇기에 파생 클래스의 leg 변수에 접근하면 error

 

[예제] upcasting 주의사항

class Animal
{
public:
    int age;
};

class Cat : public Animal
{
public:
    int leg;
};

int main()
{
    Cat c;
    Animal* p = &c;

    // error
    // p->leg = 10; 
}



[예제] static_cast 활용

class Animal
{
public:
    int age;
};

class Cat : public Animal
{
public:
    int leg;
};

int main()
{
    Cat c;
    Animal* p = &c;

    static_cast<Cat*>(p)->leg = 10; // ok
}

upcasting 활용

기반 클래스(Animal)로 부터 파생된
모든 객체를 컨테이너에 보관할 수 있다.

#include <vector>

class Animal {};
class Dog : public Animal {};
class Cat : public Animal {};

int main()
{
    std::vector<Dog*>    v1; // Dog만 보관 가능
    std::vector<Animal*> v2; // 모든 동물을 보관 가능
}



상속이 기존 타입의 확장으로도 볼 수 있지만
A와 B를 묶어서 관리하고 싶은 경우에도 활용할 수 있다. 

 


[예제]

하나의 기반 클래스로부터 파생된 클래스를 위한 공통함수

class Animal
{
public:
    int age;
};
class Cat : public Animal {};
class Dog : public Animal {};

void PlusAge(Dog* p) // Dog만 받을 수 있다.
{
    ++(p->age);

}
int main()
{
    Dog    d; PlusAge(&d); // ok
    Cat    c; PlusAge(&c); // error
    Animal a; PlusAge(&a); // error
}


void PlusAge(Dog* p) 에서는 Dog 객체만 받을 수 있지만
void PlusAge(Animal* p) 에서는 기반+파생 클래스 객체를 받을 수 있다.

[예제] upcasting 적용

class Animal
{
public:
    int age;
};
class Cat : public Animal {};
class Dog : public Animal {};

void PlusAge(Animal* p) // 모든 동물을 받을 수 있다.
{
    ++(p->age);

}
int main()
{
    Dog    d; PlusAge(&d); // ok
    Cat    c; PlusAge(&c); // ok
    Animal a; PlusAge(&a); // ok
}

static_cast 이용한 down cast

class Animal
{
public:
    int age;
};
class Cat : public Animal {};
class Dog : public Animal
{
public:
    int leg;
};

void PlusAge(Animal* p)
{
    ++(p->age);

    Dog* pDog = static_cast<Dog*>(p);
    pDog->leg = 4; // ??? -> error
}
int main()
{
    Cat    c; PlusAge(&c);
}



Cat 객체를 보내주고 Dog로 static_cast 한다면
컴파일은 성공하지만 실행하면 Error 발생!
이는 static_cast가 실제 Dog 여부 상관없이 casting 처리하기 때문이다.

dynamic_cast로 실제 객체인지 확인할 수 있다.
단, 반드시 가상함수가 한개 이상 있는 경우만 사용 가능
 (가상함수 테이블 안에 있는 타입 정보를 사용해서 객체 타입을 조사하기 때문)

class Animal
{
public:
    virtual ~Animal() {}
    int age;
};
class Cat : public Animal {};
class Dog : public Animal
{
public:
    int leg;
};

void PlusAge(Animal* p)
{
    ++(p->age);

    // 실체 객체가 Dog가 아니라면 0 반환
    Dog* pDog = dynamic_cast<Dog*>(p);
    if (pDog != nullptr)
    {
        pDog->leg = 4; // error
    }
}
int main()
{
    Cat    c; PlusAge(&c);
}



dynamic_cast
→ 실행 시 조사하기 때문에 overhead가 크다. (속도가  상대적으로 느리다.)

static_cast
→ 컴파일 시간에 조사하기 때문에 overhead가 적다

실제 객체를 보장할 수 있다면 static_cast 사용하는 것이 좋지만
그렇지 않다면 안정성을 위해서는 dynamic_cast 사용하는 것이 좋다.

 

 

📌 [C++] static_cast 사용 방법 및 필요성

 

[C++] static_cast 사용 방법 및 필요성

static_cast 필요성C 언어에서도 type casing 가능하지만논리적으로 위험한 캐스팅을 대부분 허용해서개발자 의도 인지 실수 인지 구분하기 어렵다.  [예제 코드]void* -> 다른 타입으로 캐스팅하는 것

zoosso.tistory.com

반응형

댓글