[ex02: This code is unclean. PURIFY IT!]
우주를 지키는 두 종류의 마린 유닛 클래스가 있고 이들을 묶는 스쿼드 클래스가 존재한다. 두 유닛 클래스와 스쿼드 클래스는 각각의 인터페이스 클래스에게 상속받는다.
ISpaceMarine
인터페이스 클래스class ISpaceMarine
{
public:
virtual ~ISpaceMarine() {}
virtual ISpaceMarine* clone() const = 0;
virtual void battleCry() const = 0;
virtual void rangedAttack() const = 0;
virtual void meleeAttack() const = 0;
};
-> TacticalMarine
파생 클래스
-> AssaultTerminator
파생 클래스
ISquad
인터페이스 클래스class ISquad
{
public:
virtual ~ISquad() {}
virtual int getCount() const = 0;
virtual ISpaceMarine* getUnit(int) const = 0;
virtual int push(ISpaceMarine*) = 0;
};
Squad
파생 클래스Squad
객체 생성 후 push() 함수를 통해 스쿼드안에 마린을 넣는다. 이때,squad
객체를 소멸할 때, 그 내부의 모든 마린 객체들까지 순서대로 함께 소멸된다.int main()
{
ISpaceMarine* bob = new TacticalMarine;
ISpaceMarine* jim = new AssaultTerminator;
ISquad* vlc = new Squad;
vlc->push(bob);
vlc->push(jim);
for (int i = 0; i < vlc->getCount(); ++i)
{
ISpaceMarine* cur = vlc->getUnit(i);
cur->battleCry();
cur->rangedAttack();
cur->meleeAttack();
}
delete vlc;
return 0;
}
[output]
$> clang++ -W -Wall -Werror *.cpp
$> ./a.out | cat -e
Tactical Marine ready for battle!$
* teleports from space *$
For the holy PLOT!$
* attacks with a bolter *$
* attacks with a chainsword *$
This code is unclean. PURIFY IT!$
* does nothing *$
* attacks with chainfists *$
Aaargh...$
I'll be back...$
cpp에서의 인터페이스는 가상 소멸자
와 순수 가상 함수
만 선언되어 있는 클래스이다. interface class를 사용하는 이유는 여러이유가 있지만 그중 하나는 이 클래스를 보면서 이 클래스를 상속받는 클래스들은 뭐를 하겠구나 한눈에 알수 있게 된다.
class IClass
{
public:
virtual ~IClass();
virtual void myFunc1() = 0;
...
};
순수 가상 함수만으로 구성되어 있기 때문에 당연히 스스로 인스턴스를 생성할 수 없다. 해당 인터페이스를 상속받은 자식에서 반드시 구현을 해야 한다.
추상 클래스와 크게 무엇이 다른가 싶지만, 바람직한 추상 클래스 == 인터페이스 라고 생각하면 될 것 같다. 불필요한 데이터를 상속하지 않을 수 있고, 다형성을 함수 오버로딩을 어느 특정 클래스에서만 빼먹는 실수를 방지할 수 있다.
인터페이스 클래스를 하나 만들어 놓고, 일반적인 클래스들을 다중 상속을 통해 사용하게 된다면 좋은 디자인 패턴을 가진 프로그램을 설계할 수 있을 것이다.