CPP Module 04 문제 메모

하위 유형 다형성, 추상 클래스, 인터페이스

모든 exercise에서, 당신의 main은 모든 것을 테스트해야 합니다.
각 클래스의 생성자 및 소멸자에는 무언가 특정한 출력이 있어야 합니다.


ex00

간단하고 완벽한 기본 클래스 Animal 작성. Animal 클래스는 1개의 보호된(protected) 특성을 가짐.

  • std::string type;

Animal 클래스

  • Animal 상속 Dog 클래스, Animal 상속 Cat 클래스.
  • Animal 클래스는 type을 비워두거나 아무 값을 지정해도 됨.

모든 클래스는 type 필드에 이름을 입력해야함. 예를 들어서, Dog 클래스의 type는 “Dog” 여야 함.

모든 AnimalmakeSound() 메서드를 사용할 수 있어야 함. 이 메서드는 클래스를 기준으로 표준 출력에 적절한 메시지를 표시함.

int main() {
    const Animal* meta = new Animal();
    const Animal* j = new Dog();
    const Animal* i = new Cat();
    std::cout << j->getType() << " " << std::endl;
    std::cout << i->getType() << " " << std::endl;
    i->makeSound(); //will output the cat sound!
    j->makeSound();
    meta->makeSound();
    ...
}

이것은 Animal 클래스가 아닌 DogCatmakeSound를 출력해야 함.

동일 조건에서 테스트 해볼 때, WrongAnimalmakeSound() 를 출력하는 WrongAnimal 클래스를 만들어야함.
또한, 이를 상속하는 WrongCat 클래스를 만듭니다.

  • WrongAnimal, WrongCat을 만들 때는 virtual 키워드를 빼고 만들어 보아야 함.

ex01

Ex00의 클래스들을 재사용.

  • Brain이라는 클래스를 만듦.
  • Brainideas 라는 이름의 std::string 100개짜리 배열임.
  • 그리고 DogCat은  private Brain  Attribute을 가짐.

(⚠ 모든 동물이 brain을 갖고 있지는 않음.)

  • 생성되면 DogCat은 자기의 Brainnew Brain() 으로 초기화 함.
  • 파괴되면 DogCat은 자기의 Braindelete 함.
  • 당신의 main은 Animal의 배열을 만들고 채울 것임. 절반은 Dog이고, 나머지 절반은 Cat.
  • 종료하기 전에, main은 이 배열 위로 루프하고 모든 동물을 delete 함. CatDogAnimal로써 직접 delete 해야함.
  • Cat 또는 Dog 의 복사는 “deep” 해야 함. 당신의 테스트 역시도 이것이 deep 한지를 보여주어야 함.
  • 각 클래스의 생성자 및 소멸자에는 특정 출력이 있어야 함. 적절한 소멸자들을 호출해야만 함.
int main()
{
    const Animal* j = new Dog();
    const Animal* i = new Cat();
    delete j;//should not create a leak
    delete i;
}

ex02 추상 클래스

일반화된 ‘동물’은 모순적이다. 예를 들어, 그것 자체로는 소리를 내지 못한다.

추후에 이런 실수를 방지하기 위해, 기본 Animal 클래스는 인스턴스화 될 수 없어야만 함.

Animal 클래스를 수정해서 누군가 실수로 인스턴스화 하는 것을 방지하면 됨.

나머지는 이전처럼 작동해야 함.


ex03

C++98에는 인터페이스가 없음. (심지어 C++20에도 없음). 하지만 순수 추상 클래스(pure abstract class)를 인터페이스라고 부르는 게 일반적임.

AMateria 클래스의 정의를 완성하고, 필요한 멤버 함수의 구현을 완료 해야함.

class AMateria
{
protected:
   [...]
public:
   AMateria(std::string const & type);
   [...]

   std::string const & getType() const; //Returns the materia type
   virtual AMateria* clone() const = 0;
   virtual void use(ICharacter& target);
};

속성(Materia) Ice, Cure를 만듦. 이 유형들은 lowercase의 이름을 가짐. (Ice는 “ice”, 등등..)

clone() 메서드가 있고, 이것은 당연히 실제 속성(Materia) 유형의 새로운 인스턴스를 반환함.

use(ICharacter&) 메서드를 사용하면, 다음과 같이 출력함.

  • Ice: “* shoots an ice bolt at NAME *”
  • Cure: “* heals NAME’s wounds *”

(물론, NAME 은 인자로 주어진 Character에서 얻어와 대치해야함.)

(⚠️ 속성(Materia)을 다른 속성에 대입(assigning)하면서, 유형을 복사하는 것은 의미가 없습니다…)

Character 클래스를 만듦. 다음을 구현해야 함.

class ICharacter
{
public:
    virtual ~ICharacter() {}
    virtual std::string const & getName() const = 0;
    virtual void equip(AMateria* m) = 0;
    virtual void unequip(int idx) = 0;
    virtual void use(int idx, ICharacter& target) = 0;
};

캐릭터는 처음에 최대 4개의 비어있는 속성(Materia) 인벤토리를 가짐. 그리고 속성(Materia)을 슬롯 0에서 슬롯 3까지 순서대로 장착함.

만약 인벤토리가 가득 찬 상태에서 장착하려고 하거나, 없는 속성(Materia)을 사용/장착해제 하려고 했을 땐 아무 것도 하지 않아야 함.

장착해제 메서드는 절대 속성(Materia)delete 해서는 안됨.

use(int, ICharacter&) 메서드는 idx 슬롯의 속성(Materia)을 사용해야만 함. 그리고 targetAMateria::use 메서드의 인자로 넘겨야 함.

(⚠️ 물론, 캐릭터의 인벤토리는 어떠한 AMateria도 지원할 수 있게 해야함.)

당신의 Character는 이름을 인자로 받는 생성자를 가지고 있어야 함.

당연히 Character의 복사 또는 대입(assignation) 역시도 “deep” 해야함.

Character의 예전 속성(Materia)는 삭제되어야만 함. 캐릭터의 소멸에서도 같아야 함.

다음 인터페이스를 구현하는 MateriaSource 클래스를 만듦.

class IMateriaSource
{
public:
   virtual ~IMateriaSource() {}
   virtual void learnMateria(AMateria*) = 0;
   virtual AMateria* createMateria(std::string const & type) = 0;
};

learnMateria 함수는 인자의 Materia를 복사해야하며, 나중에 복제하기 위해 메모리에 저장해야 함. Character 와 거의 같은 방식으로, Source는 최대 4개의 속성(Materia)를 알 수 있으며, 반드시 고유할 필요는 없음.

createMateria(std::string const &) 는 새로운 속성(Materia)를 반환함. 이 속성(Materia)은 유형이 인자와 동일한 속성(Materia)(Source에서 이전에 learnMateria 했던.)의 복사본이 됨. 타입을 알 수 없는 경우에는 0이 반환됨.

간단히 말해서, Source속성(Materia)의 “템플릿”을 학습하고, 필요에 따라 재생성할 수 있어야 함. 그러면 속성(Materia)의 “실제” 유형을 몰라도, 그냥 문자열(string) 만으로 식별할 수 있게 됨.

늘 그렇듯, 다음과 같이 처리해야 할 테스트 메인이 있음.

int main()
{
    IMateriaSource* src = new MateriaSource();
    src->learnMateria(new Ice());
    src->learnMateria(new Cure());

    ICharacter* me = new Character("me");

    AMateria* tmp;
    tmp = src->createMateria("ice");
    me->equip(tmp);
    tmp = src->createMateria("cure");
    me->equip(tmp);

    ICharacter* bob = new Character("bob");

    me->use(0, *bob);
    me->use(1, *bob);

    delete bob;
    delete me;
    delete src;

    return 0;
}

출력:

$> clang++ -W -Wall -Werror *.cpp
$> ./a.out | cat -e
* shoots an ice bolt at bob *$
* heals bob's wounds *$

댓글

Designed by JB FACTORY