[디딤돌 C++] 21. 캡슐화 실습2 – 학생

이번 실습은 학생 클래스를 캡슐화하는 실습입니다. 이번에는 시나리오를 보고 클래스 다이어그램을 작성한 후에 이를 구현해 보기로 해요.

  1. 시나리오

학생은 생성할 때 학생 이름을 전달받습니다. 그리고 학생 번호는 순차적으로 부여합니다. 이 외에 학생의 국어, 영어, 수학 성적을 -1로 설정합니다.

학생을 생성한 후에는 학생의 국어, 영어, 수학 성적을 입력할 수 있습니다. 만약 학생 성적이 0에서 100을 벗어나면 -1로 설정합니다.

학생 이름과 번호, 각 과목의 성적과 총점 및 평균을 확인할 수 있습니다. 그리고 전체 학생 수를 확인할 수 있습니다. 그리고 학생 정보를 출력하는 기능을 제공합니다.

  1. 클래스 다이어그램으로 나타내기

먼저 클래스 이름을 결정해야겠죠.

멤버 필드에는 번호와 이름이 있어야 합니다. 번호는 값을 변경하지 못하게 상수화 멤버 필드로 정하면 신뢰성을 높일 수 있겠죠. 이 외에 학생 개체에는 국, 영, 수 성적을 보관하는 멤버가  필요합니다. 성적을 보관하는 멤버는 배열로 선언하기로 해요.

그런데 학생 번호를 순차적으로 부여하려면 최근에 부여한 학생 번호가 필요하겠죠. 이 멤버는 개체마다 갖을 필요가 없으며 형식에 유일하게 부여할 멤버이므로 정적 멤버로 정하세요.

학생 클래스 다이어그램

클래스 다이어그램에서 정적 멤버는 밑줄이 그어집니다.

멤버 메서드에는 먼저 이름을 입력 인자로 받는 생성자가 필요하겠죠. 그리고 성적을 설정하는 메서드가 필요해요. 또한 성적은 배열로 관리하므로 성적을 설정하는 메서드는 과목을 나타내는 인덱스와 성적을 입력 인자로 받게 정하기로 합시다. 이 메서드에 전달받은 성적이 유효하면 전달받은 값으로 벗어났을 때 -1으로 성적을 설정하는 메서드도 제공합시다. 대신 이 메서드는 접근 지정을 private으로 설정하여 형식 외부에서 잘못된 값으로 설정하지 못하게 하세요.

과목을 나타내는 인덱스와 성적은 유효 범위가 있으므로 범위를 벗어나는지 확인하는 메서드를 각각 제공하기로 해요.

그리고 이름과 번호를 확인할 수 있는 메서드를 제공하세요. 성적을 확인하는 메서드는 과목을 나타내는 인덱스를 전달받아 성적을 반환하기로 해요.

그리고 평균과 총점을 확인하는 메서드와 현재 학생 수를 확인하는 메서드를 제공합시다. 현재 학생 수를 확인하는 메서드는 정적 메서드로 정의하는 것이 바람직하겠죠.

마지막으로 자신의 정보를 출력하는 메서드를 제공하세요.

학생 클래스 다이어그램
  1. 구현

이제 구현해 보세요. 여러분께서 먼저 구현한 후에 비교해 보세요.

//Student.h
#pragma once
#include <string>
#include <iostream>
using namespace std;

enum SIndex //과목 열거형
{
    KOREAN, ENGLISH, MATH, MAX_SUBJECT
};

class Student//학생 클래스
{
    static int last_num;//정적 멤버 필드   
    const int num;//상수화 멤버 필드
    string name;
    int scores[MAX_SUBJECT];
    static const string titles[MAX_SUBJECT];//과목명 - 정적 멤버 필드
public:
    static int GetStuCount();//정적 메서드   
    Student(string name);//생성자 초기화   
    bool SetScore(int sindex,int score);//성적 설정자
    int GetScore(int sindex)const;//성적 접근자
    int GetTotal()const;//총점 접근자
    double GetAverage()const;    //평균 접근자
    bool AvailSIndex(int sindex)const;//성적 인덱스가 유효한지 판별
   void View()const; //정보 출력
private:
    bool SetScore(int sindex,int score,int); //성적 설정자
};
//Student.cpp
#include "Student.h"

const string Student::titles[MAX_SUBJECT]={"국어","영어","수학"};
int Student::last_num;

int Student::GetStuCount()//정적 메서드
{
    return last_num;
}

Student::Student(string name):num(++last_num)//생성자 초기화
{
    this->name = name;
    //성적 초기화
    for(int si = 0; si<MAX_SUBJECT; si++)
    {
        SetScore(si,-1, 0);
    }
}

bool Student::SetScore(int sindex,int score)//성적 설정자(설정하기)
{
    if(AvailSIndex(sindex))//과목 번호가 유효할 때
    {
        return SetScore(sindex,score,0);//성적 설정
    }   
    return false;
}

int Student::GetScore(int sindex)const//성적 접근자(가져오기)
{
    if(AvailSIndex(sindex))//과목 번호가 유효할 때
    {
        return scores[sindex];
    }
    return -1;
}

int Student::GetTotal()const//합계 접근자(가져오기)
{
    int sum=0;
    for(int i = 0; i<MAX_SUBJECT; i++)
    {
        if(scores[i] != -1)//성적이 입력 상태일 때만
        {
            sum +=scores[i];//합계에 더함
        }
    }
    return sum;
}

double Student::GetAverage()const//평균 접근자(가져오기)
{
    return GetTotal()/(double)(MAX_SUBJECT);
}   

bool Student::AvailSIndex(int sindex)const//과목 인덱스가 유효한지 판별
{
    return (sindex>=0)&&(sindex<MAX_SUBJECT);
}

void Student::View()const
{
    cout<<"번호:"<<num<<" 이름:"<<name<<endl;
    for(int i = 0; i<MAX_SUBJECT;i++)
    {
        if(scores[i]==-1)
        {
            cout<<titles[i]<<": 입력 안 함"<<endl;
        }
        else
        {
            cout<<titles[i]<<":"<<scores[i]<<endl;
        }
    }
    cout<<"총점:"<<GetTotal()<<" 평균:"<<GetAverage()<<endl;
    cout<<"++++++++++++++++++++++++"<<endl;
}

bool Student::SetScore(int sindex,int score,int)//성적 설정자(설정하기)
{
    if((score<0)||(score>100))//성적이 범위를 벗어나면
    {
        scores[sindex] = -1;
        return false;
    }
    scores[sindex] = score;
    return true;
}
//Program.cpp
#include "Student.h"

int main()
{
    Student *arr[3];

    //학생 개체 생성
    arr[0] = new Student("홍길동");
    arr[1] = new Student("강감찬");
    arr[2] = new Student("이순신");

    //학생 목록 출력
    cout<<"현재 학생 수:"<<Student::GetStuCount()<<endl;
    for(int i = 0; i<3;i++)
    {
        arr[i]->View();
    }

    arr[0]->SetScore(0,90);//정상
    arr[0]->SetScore(1,80);//정상
    arr[0]->SetScore(3,90);//설정 오류
    arr[1]->SetScore(0,100);//정상
    arr[1]->SetScore(1,180);//설정 오류
    arr[1]->SetScore(2,80);//정상

    arr[2]->SetScore(0,80);//정상
    arr[2]->SetScore(1,90);//정상
    arr[2]->SetScore(2,90);//설정 오류

    //학생 목록 출력
    cout<<"현재 학생 수:"<<Student::GetStuCount()<<endl;
    for(int i = 0; i<3;i++)
    {
        arr[i]->View();
    }

    //학생 개체 소멸
    for(int i = 0; i<3;i++)
    {
        delete arr[i];
    }

    return 0;
}

▷ 실행 결과

현재 학생 수:3

번호:1 이름:홍길동

국어: 입력 안 함

영어: 입력 안 함

수학: 입력 안 함

총점:0 평균:0

++++++++++++++++++++++++

번호:2 이름:강감찬

국어: 입력 안 함

영어: 입력 안 함

수학: 입력 안 함

총점:0 평균:0

++++++++++++++++++++++++

번호:3 이름:이순신

국어: 입력 안 함

영어: 입력 안 함

수학: 입력 안 함

총점:0 평균:0

++++++++++++++++++++++++

현재 학생 수:3

번호:1 이름:홍길동

국어:90

영어:80

수학: 입력 안 함

총점:170 평균:56.6667

++++++++++++++++++++++++

번호:2 이름:강감찬

국어:100

영어: 입력 안 함

수학:80

총점:180 평균:60

++++++++++++++++++++++++

번호:3 이름:이순신

국어:80

영어:90

수학:90

총점:260 평균:86.6667

++++++++++++++++++++++++