[디딤돌 C++] 40. 상속과 다형성 실습2 (도형)

도형 클래스 다이어그램

이번 실습은 도형을 소재로 할게요. 위 그림은 Visual Studio에서 제공하는 기능을 사용하여 출력한 클래스 다이어그램입니다.

시나리오

  1. 도형

도형 ID를 순차적으로 부여합니다.

순수 가상 메서드로 Draw 메서드를 제공합니다.

파생 형식에서도 접근 가능한 GetID 접근자를 제공합니다.

x와 y 좌표 멤버를 갖습니다.

생성자에서 x, y 좌표를 입력 인자로 받습니다.

Draw 메서드를 재정의합니다.

두 개의 점을 멤버로 갖습니다.

생성자에서 두 점의 x, y 좌표를 입력 인자로 받습니다.

Draw 메서드를 재정의합니다.

여러분께서 먼저 작성해 본 후에 비교해 보세요. 작성하다 막히면 앞에 상속과 다형성에 관한 내용을 보시면서 하시기 바랍니다. 여기에 작성한 것을 보면서 그대로 따라하는 것은 큰 의미가 없어요.

  1. IGetArea

GetArea 순수 가상 메서드를 멤버로 갖는 인터페이스입니다.

5.사각형

왼쪽 상단 좌표(left, top)와 우측 하단 좌표(right, bottom)를 멤버로 갖습니다.

생성자에서 왼쪽 상단 좌표와 우측 하단 좌표를 입력 인자로 받습니다.

Draw 메서드와 GetArea 메서드를 재정의합니다.

다음은 이를 사용하는 코드입니다.

void TestGetArea(IGetArea *iga)
{
    cout<<"  면적:"<<iga->GetArea()<<endl;;
}

int main()
{
    Diagram *diagrams[3];
    diagrams[0] = new Point(3,4);
    diagrams[1] = new Line(0,0,5,5);
    diagrams[2] = new Rectangle(0,0,10,10);
    for(int i = 0; i<3; i++)
    {
        diagrams[i]->Draw();
        IGetArea *iga = dynamic_cast<IGetArea *>(diagrams[i]);
        if(iga)
        {
            TestGetArea(iga);
        }        
    }
    for(int i = 0; i<3; i++)
    {
        delete diagrams[i];
    }
    return 0;
}

다음은 실행 결과입니다.

1 점(3,4)

2 선

3 점(0,0)

4 점(5,5)

5 사각형(0,0)(10,10)

면적:100

클래스 다이어그램를 보고 사용하는 코드를 이용하여 실행 결과처럼 출력하는 프로그램을 작성하세요. 마찬가지로 모르는 부분은 앞에 상속과 다형성에 관한 부분을 보시면서 해도 괜찮아요. 하지만 여기에 작성한 코드를 보면서 따라 작성하는 것은 큰 의미가 없습니다.

다음은 예제 코드입니다.

//상속과 다형성 실습 2(도형)
#include <iostream>
using namespace std;

class Diagram
{
    static int last_id; //가장 최근에 부여한 ID (정적 멤버)
    const int id; //ID (상수화 멤버)
public:
    Diagram():id(++last_id)//상수화 멤버 초기화
    {
    }
    virtual void Draw()=0;//순수 가상 메서드
protected: 
    int GetID()const //ID 접근자
    {
        return id;
    }
};
int Diagram::last_id; //정적 멤버 필드 선언

class Point:public Diagram
{
    int x,y;
public:
    Point(int x,int y)
    {
        this->x = x;
        this->y = y;
    }
    virtual void Draw()//재정의
    {
        cout<<GetID()<<" 점("<<x<<","<<y<<")"<<endl;
    }
};

class Line:public Diagram
{
    Point *p1;
    Point *p2;
public:
    Line(int x1,int y1, int x2,int y2)
    {
        p1 = new Point(x1,y1);
        p2 = new Point(x2,y2);
    }
    ~Line()
    {
        delete p1;
        delete p2;
    }
    virtual void Draw()//재정의
    {
        cout<<GetID()<<" 선"<<endl;
        cout<<"  ";
        p1->Draw();
        cout<<"  ";
        p2->Draw();
    }
};

#define interface struct
interface IGetArea //인터페이스
{
    virtual int GetArea()const=0; //순수 가상 메서드
};

class Rectangle: public Diagram, public IGetArea
{
    int left, top, right, bottom;
public:
    Rectangle(int left, int top, int right, int bottom)
    {
        this->left = left;
        this->top = top;
        this->right = right;
        this->bottom = bottom;
    }
     virtual void Draw()//재정의
     {
         cout<<GetID()<<" 사각형";
         cout<<"("<<left<<","<<top<<")"<<"("<<right<<","<<bottom<<")"<<endl;
     }

     virtual int GetArea()const//재정의
     {
         int width = right- left;
         if(width<0) //폭이 음수일 때
         {
             width = -width; //양수로 전환
         }

         int height = bottom-top;
         if(height<0) //폭이 음수일 때
         {
             height = -height; //양수로 전환
         }
         return width * height;
     }    
};

void TestGetArea(IGetArea *iga)
{
    cout<<"  면적:"<<iga->GetArea()<<endl;;
}

int main()
{
    Diagram *diagrams[3];
    diagrams[0] = new Point(3,4);
    diagrams[1] = new Line(0,0,5,5);
    diagrams[2] = new Rectangle(0,0,10,10);
    for(int i = 0; i<3; i++)
    {
        diagrams[i]->Draw();
        IGetArea *iga = dynamic_cast<IGetArea *>(diagrams[i]);
        if(iga)
        {
            TestGetArea(iga);
        }        
    }
    for(int i = 0; i<3; i++)
    {
        delete diagrams[i];
    }
    return 0;
}