[디딤돌 C++] 77. 최종 실습 – 학생 이동

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

시나리오를 보면 먼저 이동할 장소를 선택하고 이동할 학생을 선택합니다. 그리고 해당 장소로 학생을 이동합니다.

시퀀스 다이어그램

만약 이동할 장소가 학교일 때는 처음 온 학생인지 확인하여 학번을 부여합니다. 처음 온 학생이라면 학번이 0일 것입니다. 이럴 때는 학번을 부여합니다.

시퀀스 다이어그램

EhNara의 멤버 MoveStudent를 구현합시다.

void EhNara::MoveStudent() //학생 이동
{
먼저 이동할 장소를 선택합니다.
    Place *place = SelectPlace();//이동할 장소 선택
잘못 선택하였을 때 메시지를 출력하고 메서드를 끝냅니다.
    if(place==0)//잘못 선택하였을 때
    {
        cout<<"잘못 선택하였습니다."<<endl;
        return;
    }
이동할 학생을 선택합니다.
    Student *stu = SelectStudent();//이동할 학생 선택
잘못 선택하였을 때 메시지를 출력하고 메서드를 끝냅니다.
    if(stu == 0)
    {
        cout<<"잘못 선택하였습니다."<<endl;
        return;
    }
선택한 학생을 EhNara에서 제거하고 선택한 장소로 이동합니다.
    EraseStudent(stu);//학생 제거
    place->InStudent(stu);//선택한 장소로 학생 이동
}

EhNara 클래스에 이동할 학생을 선택하는 SelectStudent 메서드와 컬렉션에서 학생 제거하는 EraseStudent 메서드를 추가합니다.

class EhNara:public IComeBack
{
    ...중략...
private:
    ...중략...
    Student *SelectStudent();//이동할 학생 선택 
    void EraseStudent(Student *stu);//학생 제거
};

EhNara의 멤버 SelectStudent를 구현합시다. 참고로 현재 실습에서 시퀀스 다이어그램에서는 서로 다른 개체 사이에서의 상호 작용에 관한 것만 표시하고 있습니다.

Student *EhNara::SelectStudent()//이동할 학생 선택    
{
최종 사용자에게 선택할 학생의 주민번호를 입력받습니다.
    cout<<"선택할 학생의 주민번호:";
    int pn=0;
    cin>>pn;
컬렉션에서 입력한 주민번호와 같은 학생 개체를 찾아 반환합니다.
    size_t size = base.GetSize();//보관한 학생 수 구하기
    for(size_t i=0;i<size;++i)
    {
        if(base[i]->GetPN() == pn)//학생 주민번호와 입력한 주민번호가 같을 때
        {
            return base[i];
        }
    }
없을 때는 0을 반환합니다.
    return 0;
}

EhNara의 멤버 EraseStudent 메서드를 구현합시다.

void EhNara::EraseStudent(Student *stu)//학생 제거
{
컬렉션에서 입력 인자로 받은 학생 개체를 보관한 인덱스를 찾습니다.
    size_t size = base.GetSize();//보관한 학생 수 구하기
    for(size_t i=0;i<size;++i)
    {
        if(base[i]==stu)//보관한 학생과 입력 인자로 받은 학생이 같을 때
        {
찾았다면 해당 인덱스에 보관한 것을 지웁니다.
            base.RemoveAt(i);//해당 인덱스에 보관한 개체 지우기
            return;
        }
    }
}

이제 Place 클래스에 유닛 이동 메서드인 InStudent를 선언하세요. 학교에서는 학번을 부여하는 역할을 추가로 해야 하므로 가상 메서드로 정의하세요. 그리고 유닛을 보관할 컬렉션을 멤버 필드로 선언하세요.

class Place
{
    ...중략...
    SeqArray<Man *> base;
public:
    ...중략...
    virtual void InStudent(Man *man);//유닛 이동
    ...중략...
};

Place 클래스의 멤버 InStudent 메서드에서는 컬렉션에 유닛을 순차 보관하세요.

void Place::InStudent(Man *man)//유닛 이동
{
    base.PushBack(man);
}

School 클래스에서 InStudent 메서드를 재정의해야겠죠. 그리고 학번을 부여하기 위해 가장 최근에 부여한 학번을 기억하는 멤버 필드를 선언하세요.

class School :
    public Place
{
    int last_snum;//가장 최근에 부여한 학생 번호
public:
    ...중략...
    virtual void InStudent(Man *man);//유닛 이동
    ...중략...
};

School 클래스 생성자에서 가장 최근에 부여한 학번을 0으로 설정하세요.

School::School(IComeBack &ic):Place(ic)
{
    last_snum = 0;
}

School 클래스의 InStudent 메서드를 구현합시다.

void School::InStudent(Man *man)//유닛 이동
{
기반 형식인 Place의 InStduent 메서드를 호출합니다. 이 부분은 컬렉션에 보관하는 역할을 하는 것이죠.
    Place::InStudent(man);//기반 형식 Place의 InStudent를 호출(컬렉션에 보관)
처음 온 학생인지 확인하기 위해 학번을 확인합니다. 그리고 처음 온 학생이면 학번을 부여하세요.
    if(man->GetSNum()==0)//처음 온 학생이면
    {
        last_num++;
        man->SetSNum(last_snum);//학번 부여
    }
}

Man 클래스에 학번을 멤버 필드로 추가하세요. 그리고 학번 접근자와 설장자를 추가하세요.

class Man
{
    ...중략...
    int snum;//학번
public:
    ...중략...
    int GetSNum()const;//학번 접근자
    void SetSNum(int snum); //학번 설정자
};

Man 클래스 생성자에서 학번을 0으로 설정하세요.

Man::Man(string name):pn(last_pn)
{
    snum = 0;
}

Man 클래스의 학번 접근자와 설정자를 구현하세요.

int Man::GetSNum()const//학번 접근자
{
    return snum;
}
void Man::SetSNum(int snum) //학번 설정자
{
    this->snum = snum;
}

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