원과 타원의 클래스를 만들어보겠다. 우리가 배운 상속을 이용해서 만들어보자. 그럼 누가 기초 클래스가 되어야 하는가? 가만 보면 타원이 원을 포함한다. 타원에서 장경과 단경이 같으면 원이기 때문이다. 그러므로 타원을 기초 클래스로 해보겠다.
class Ellipse
{
private:
double x; // 타원 중심의 x 좌표.
double y; // 타원 중심의 y 좌표.
double a; // 반장경
double b; // 반단경
double angle; // 각도 단위의 방위각.
public:
void Move(int nx, int ny) { x = nx; y = ny; } // 중심 옮기기.
virtual double Area() const { return 3.141592 * a * b; } // 면적 구하기.
virtual void Rotate(double nang) { angle += nang; } // 회전 시키기.
virtual void Scale(double sa, double sb) { a *= sa; b *= sb; } // 크기 조정.
};
자~ 이제 한번 기초 클래스를 상속시켜 보겠다.
class Circle : public Ellipse
{
...
};
사실 상속시키기 좀 어색하다. 왜? Ellipse 클래스는 반장경 반당경 두 변수가 있는 반면, 원은 반지름 하나면 충분하다. 또한 angle 변수와 Rotate 함수는 전혀 의미가 없다. 잘못해서 Sclae 함수에 각각 다른 매개 변수를 넣는다면 갑자기 타원이 돼버린다. 이럴 바에는 그냥 상속하지 않고 정의하는 게 나아보인다.
class Circle
{
private:
double x;
double y;
double r;
public:
void Move(int nx, int ny) { x = nx; y = ny; }
double Area() const { return 3.14159 * r * r; }
void Scale(double sr) { r *= sr; }
};
상속이 필요 없을 것 같아서 따로 정의 했는데, 가만 보니 겹치는 함수가 있긴 하다. 근데 상속은 좀 애매하고... 어떻게 해야 할까?
그래서 나온 것이 바로 이 추상화 기초 클래스(추상 클래스)다. 두 클래스의 공통적인 부분만 기초 클래스에 넣고, Circle, Ellipse 두 클래스 모두 그 기초 클래스로부터 파생시키는 것이다. 그리고 이것이 바로 다형적인 접근이다. 공통적인 부분만 뽑아서 추상 클래스를 만들어 보자.
class BaseEllipse
{
private:
double x;
double y;
public:
BaseEllipse(double x0 = 0, double y0 = 0)
: x(x0), y(y0)
{}
virtual ~BaseEllipse() {}
void Move(int nx, int ny) { x = nx; y = ny; }
virtual double Area() const = 0; // 순수 가상 함수.
};
Move 함수는 둘 다 똑같이 쓰이기 때문에 재정의 할 필요가 없어서 저렇게 구현 했다. 그 밑의 Area 함수는 필요한 데이터 멤버가 없기 때문이 정의할 수가 없다. 그런 경우를 위해서 순수 가상 함수를 만들었다. 저런식으로 맨 앞에는 'virtual'를, 맨 뒤에는 '=0'을 붙이면 된다. 이는 파생 클래스에서 무조건! 재정의 해달라는 의미이다. 파생 클래스의 'public 추상클래스' 부분에서 'Ctrl.'을 누르면 쉽게 가상 함수를 선언해준다. 그 코드에는 override가 붙었는데, 이는 순수 가상 함수를 받았다는 의미이다.
추상 클래스는, 그 클래스의 객체는 만들 수 없다. 왜? '추상 클래스 → 순수 가상 함수를 하나 이상 가지고 있다. → 기초 클래스를 목적으로 사용할거다.'라는 의미이기 때문이다.
가상 함수를 쓰지 않으면 그대로 쓰겠다는 건데, 순수 가상 함수로 만들어 놓고 정의를 따로 해도 된다.
Ellipse.h
class BaseEllipse
{
virtual void Move(int nx, int ny) = 0; // 순수 가상 함수.
};
Ellipse.cpp
void BaseEllipse::Move(int nx, int ny)
{
x = nx;
y = ny;
}