본문 바로가기
  • 쓸쓸한 개발자의 공부방
C++

[C++] 디자인패턴 : uscasting

by 심찬 2022. 1. 28.

 

[C++] 디자인패턴 : uscasting 

 

 

upcasting

 

기반 클래스 타입의 포인터(참조)로 파생 클래스 객체를 가리킬 수 있다.

 

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

int main()
{
    Dog d;

    Dog*    p1 = &d;  // ok.

    double* p2 = &d;  // error.

    Animal* p3 = &d;  // ok.
}

 

Dog 형태의 d 는 age, color를 가지고 있다. 

Animal p3에를 메모리를 찾아가면 age 존재하기 때문에 문제가 없다.

 

 

 

 

폴더와 파일의 관계를 생각해볼 수 있다.

폴더는 폴더 안에 폴더와 파일을 가질 수 있다.

그래서 폴더와 파일을 동시에 가질 수 있는 기반 객체 Item을 만들어 둘 다 허용할 수 있다.

즉, Folder에 File뿐 아니라 Folder도 보관하려면 File과 Folder는 공통의 기반 클래스 Item이 있어야 한다.

 

 

upcasting 과 virtual

 

아래 코드의 Cry()는 virtual이 없다. 즉 가상 함수가 아니다.

이런 경우 p->Cry();를 호출했을 때 아래의 결과 처럼 Animal Cry가 출력된다.

#include <iostream>
using namespace std;

class Animal
{
    int age;
public:
    void Cry() { cout << "Animal Cry" << endl;}
};

class Dog : public Animal
{
    int color;
public:
    void Cry()  { cout << "Dog Cry" << endl;}
};

int main()
{
    Dog d;
    Animal* p = &d;

    p->Cry();
}

 

 

아래 처럼 Animal 기반 클래스의 Cry()가 virtual 형태인 가상 함수로 정의가 되어 있다면

아래의 결과 처럼 Dog Cry로 출력된다.

가상 함수 룰에 따라 파생 클래스로 호출됨을 알 수 있다.

 

#include <iostream>
using namespace std;

class Animal
{
    int age;
public:
    virtual void Cry() { cout << "Animal Cry" << endl;}
};

class Dog : public Animal
{
    int color;
public:
    // override
    virtual void Cry()  { cout << "Dog Cry" << endl;}
};

int main()
{
    Dog d;
    Animal* p = &d;

    p->Cry();
}

 

 

간단하지만 대형 코드를 접하다 보면 이런 사소한 부분 때문에 이해가 잘 안되는 경우가 더러 생긴다.

그만큼 기초가 중요한 이유라고 할 수 있겠다.

 

 

기반 클래스 포인터로 파생 클래스를 가리 킬 때

- 파생 클래스가 재정의 한 함수가 호출되게 하려면 반드시 가상 함수로 만들어야 한다.

 

 

 

 

댓글