[디딤돌 C++] 76. 최종 실습 – 학생 생성

이번에는 학생 생성 기능에 관해 시퀀스 다이어그램을 작성하고 난 후에 구체적인 코드를 구현합시다.

시나리오를 보면 먼저 최종 사용자로부터 학생 유형과 이름을 입력받습니다. 그리고 학생 공장에게 학생을 만들어 줄 것을 요청하면 학생 공장에서 학생을 생성하여 반환합니다.

시퀀스 다이어그램

이제 이 부분을 구현해 봅시다.

먼저 EhNara 클래스에 학생을 보관할 수 있는 컬렉션을 멤버 필드로 추가하세요.

class EhNara:public IComeBack
{
    ...중략...
    SeqArray<Student *> base;
    ...중략...
};

이제 EhNara 클래스의 멤버 MakeStudent 메서드를 구현합시다.

void EhNara::MakeStudent() //학생 생성
{
최종 사용자가 생성할 학생 유형을 선택할 수 있게 합니다.
    cout<<"생성할 학생 유형을 선택하세요. [1]:학사학생 [2]:마법학생 [3]:운동학생"<<endl;
    int stype;
    cin>>stype;
만약 잘못 선택하였다면 메시지를 출력하고 메서드를 끝내세요.
    if((stype<1)||(stype>3))//잘못 선택하였을 때
    {
        cout<<"잘못 선택하였습니다."<<endl;
        return;
    }
학생 이름을 입력받습니다.
    cout<<"학생 이름:";
    string name;
    cin>>name;
학생 공장 개체에게 학생 생성 요청하여 반환받은 학생 개체를 컬렉션에 보관합니다.
    Student *stu = sf->MakeStudent(stype,name);//학생 생성 요청
    base.PushBack(stu);//생성한 학생 보관
}

StuFactory 클래스에 MakeStudent 메서드를 선언하세요.

class StuFactory
{
    SeqArray<Student *> base;
    ...중략...
};

StuFactory 클래스의 멤버 MakeStudent를 구현합시다.

Student *StuFactory::MakeStudent(int stype,string name)//학생 생성
{
    Student *stu = 0;
입력 인자로 받은 stype에 따라 적절한 학생 개체를 생성합니다. 만약 유효하지 않은 stype일 때는 버그이므로 예외를 던집니다.
    //stype에 따라 적절한 학생 개체 생성
    switch(stype)
    {
    case 1: stu = new SStudent(name); break;
    case 2: stu = new MStudent(name); break;
    case 3: stu = new PStudent(name); break;
    default: throw "학생 타입 범위를 벗어났습니다.";
    }
생성한 학생 개체를 컬렉션에 보관하고 반환합니다.
    base.PushBack(stu);//생성한 학생 개체를 컬렉션에 보관
    return stu;//생성한 학생 개체 반환
}

StuFactory.h에서는 Student.h 파일만 포함했었는데 StuFactory.cpp에서는 파생 클래스를 생성하는 구문을 사용하였기 때문에 이들에 관한 헤더 파일 포함문을 작성하세요.

//StuFactory.cpp
#include "StuFactory.h"
#include "SStudent.h"
#include "MStudent.h"
#include "PStudent.h"

그리고 상속과 다형성 실습에서는 Man 클래스가 없었는데 여기에서는 추가하였으니 Man 클래스에 이름과 주민 번호를 멤버 필드를 추가하세요. 그리고 생성자에 이름을 입력받게 수정합시다. 소멸자는 필요없으니 제거하세요. 물론 pn값을 확인하는 접근자와 이름을 확인하는 접근자를 추가하세요. 그리고 정보를 출력하는 View 순수 가상 메서드를 선언합시다.

class Man
{
    static int last_pn;
    const int pn;
    string name;
public:
    Man(string name);
    int GetPN()const;
    string GetName()const;
virtual void View()const=0;//정보보기

};

Man.cpp 파일에 정적 멤버 pn을 선언하세요.

//Man.h
#include "Man.h"
생성자에서는 상수화 멤버 필드 pn을 초기화해야죠.
int Man::last_pn;

Man::Man(string name):pn(++last_pn)
{
}

pn 접근자와 name 접근자 메서드도 정의하세요.

int Man::GetPN()const
{
    return pn;
}
string Man::GetName()const
{
    return name;
}

Student 클래스에 pn, last_pn, name 멤버 필드를 제거하고 pn 접근자와 name 접근자를 제거하세요.

class Student:public Man, public IStudy, public IRelax, public IPlay
{
    //static int last_pn;
    //const int pn;
    //string name;
    int iq;
    int hp;
    int stress;
    int scnt;
public:    
    friend class StuFactory;
    virtual void Study()=0;
    virtual void ListenLecture()=0;
    virtual void Sleep()=0;
    virtual void Relax()=0;
    virtual void Drink()=0;
    virtual void Sing()=0;
    virtual void View()const;
    //int GetPN()const;
    //string GetName()const;
    int GetIQ()const;
    int GetHP()const;
    int GetStress()const;
    int GetSCnt()const;
protected:
    Student(string name);
    void SetIQ(int iq);
    void SetHP(int hp);
    void SetStress(int stress);
    void SetSCnt(int scnt);    
};

소스 파일에서도 이들을 제거하고 생성자에서는 Man 클래스 초기화를 하세요.

Student::Student(string name):Man(name)
{  
    SetIQ(SC::def_iq);
    SetHP(SC::def_hp);
    SetStress(SC::def_stress);
    SetSCnt(SC::def_scnt);
}

Stduent 클래스의 멤버 View 메서드에서 pn과 name을 출력하는 부분을 Man 클래스의 pn 접근자와 name 접근자 호출로 수정하세요.

void Student::View()const
{
    cout<<"주민 번호:"<<GetPN()<<" 이름:"<<GetName()<<endl;
    cout<<"  IQ:"<<iq<<" HP:"<<hp<<" Stress:"<<stress<<endl;
    cout<<"  연속으로 공부한 횟수:"<<scnt<<endl;
}

이제 컴파일하고 빌드 후에 테스트 해 보세요.