---
description: 바람직한 추상 클래스 == 인터페이스
---

# \[CPP-04  ex02] 인터페이스(Interface) 클래스

## 0. 과제 소개

**\[ex02: This code is unclean. PURIFY IT!]**

### 1) 클래스 생성

우주를 지키는 두 종류의 _마린 유닛 클래&#xC2A4;_&#xAC00; 있고 이들을 묶는 _스쿼드 클래&#xC2A4;_&#xAC00; 존재한다. 두 유닛 클래스와 스쿼드 클래스는 각각의 인터페이스 클래스에게 상속받는다.

#### 1.1) `ISpaceMarine` 인터페이스 클래스

```cpp
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` 파생 클래스
  * clone() : 현재 객체 복사본 반환, 생성 시 _"Tactical Marine ready for battle"_
  * battleCry() : _"For the holy PLOT!"_&#x20;
  * rangedAttack() : " _attacks with a bolter_ "&#x20;
  * meleeAttack() : " _attacks with a chainsword_ "&#x20;
  * 소멸자: "_Aaaragh ..._" 출력
* -> `AssaultTerminator` 파생 클래스
  * clone() : 현재 객체 복사본 반환, 생성 시: " _teleports from space_ "
  * battleCry() : "_This code is unclean. PURIFY IT!_"
  * rangedAttack : " _does nothing_ "
  * meleeAttack : " _attacks with chainfists_ "
  * 소멸: "_I’ll be back..._"

#### 1.2) `ISquad` 인터페이스 클래스

```cpp
class ISquad
{
public:
      virtual ~ISquad() {}
      virtual int getCount() const = 0;
      virtual ISpaceMarine* getUnit(int) const = 0;
      virtual int push(ISpaceMarine*) = 0;
};
```

* -> `Squad` 파생 클래스
  * getCount(): 현재 분대에 있는 유닛 수 반환.
  * getUnit(N): N 번째 포인터 반환. (0부터 시작, 범위 벗어난 인덱스 NULL 포인터)
  * push(XXX) : XXX 유닛을 스쿼드 끝에 추가, 동작 후 스쿼드 유닛 수 반환. (null유닛 or 이미 스쿼드에 있는 유닛 추가는 의미 없음)
  * 새로운 스쿼드 할당 시 이전 것은 반드시 삭제되어야함. 메모리 누출하지말고, 깊은 복사 할 것, 스쿼드가 파괴되면 내부 마린도 순서대로 파괴 (대입연산자 오버로딩에서는 이미 전에 객체가 존재하면 지우고 시작해야한다)

### 2) 과제 조건

1. 여러 종류의 마린 객체를 생성한다. 두 종류의 마린은 생성자 메세지가 달라야 한다.
2. `Squad` 객체 생성 후 push() 함수를 통해 스쿼드안에 마린을 넣는다. 이때,
   1. **깊은 복사**를 통해 넣어야 한다. (대입연산자 오버로딩할때 참조자 값만 복사하는 것이 아닌 객체 자체를 복사)
   2. 동일한 이름의 마린이나 null 마린은 당연히 스쿼드 안에 들어갈 수 없다.
3. `squad` 객체를 소멸할 때, 그 내부의 모든 마린 객체들까지 순서대로 함께 소멸된다.

### 3) 테스트 코드

```cpp
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;
}
```

```bash
[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...$
```

## 1. 인터페이스(Interface)

cpp에서의 인터페이스는 `가상 소멸자`와 `순수 가상 함수`만 선언되어 있는 클래스이다. interface class를 사용하는 이유는 여러이유가 있지만 그중 하나는 이 클래스를 보면서 이 클래스를 상속받는 클래스들은 뭐를 하겠구나 한눈에 알수 있게 된다.

```cpp
class IClass
{
    public:
        virtual ~IClass();
        virtual void myFunc1() = 0;
        ...
};
```

순수 가상 함수만으로 구성되어 있기 때문에 당연히 스스로 인스턴스를 생성할 수 없다. 해당 인터페이스를 상속받은 자식에서 반드시 구현을 해야 한다.

추상 클래스와 크게 무엇이 다른가 싶지만, **바람직한 추상 클래스 == 인터페이스** 라고 생각하면 될 것 같다. 불필요한 데이터를 상속하지 않을 수 있고, 다형성을 함수 오버로딩을 어느 특정 클래스에서만 빼먹는 실수를 방지할 수 있다.

인터페이스 클래스를 하나 만들어 놓고, 일반적인 클래스들을 다중 상속을 통해 사용하게 된다면 좋은 디자인 패턴을 가진 프로그램을 설계할 수 있을 것이다.
