C & C++/디딤돌 C++

[C++] 23. 캡슐화 최종 실습 – 멤버 필드 24. 멤버 메서드 25. 테스트 코드 작성

언휴 2024. 4. 7. 04:07

 

[C++] 캡슐화 최종 실습 – 멤버 필드

 23. 캡슐화 최종 실습 – 멤버 필

먼저 클래스 이름은 Student로 정할게요.

주민 번호는 변하지 않으므로 상수화 멤버 필드로 정의하세요.

const int pn;//주민번호

주민 번호를 순차적으로 부여하기 위해 정적 멤버 필드로 가장 최근에 부여한 주민 번호가 필요하겠죠.

static int last_pn;//가장 최근에 부여한 주민 번호

이름은 문자열로 정하면 되겠죠.

string name;//이름

지력과 체력, 스트레스, 연속으로 공부한 횟수는 정수 형식으로 정의하면 되겠네요.

int iq;//지력
int hp;//체력
int stress;//스트레스
int scnt;//연속으로 공부한 횟수

최소값, 최대값, 디폴트 값은 형식 내에 정해진 값이므로 정적 상수화 멤버 필드로 선언하세요.

//능력치의 디폴트, 최소, 최대값
static const int def_iq;
static const int min_iq;
static const int max_iq;

static const int def_hp;
static const int min_hp;
static const int max_hp;

static const int def_stress;
static const int min_stress;
static const int max_stress;

static const int def_scnt;
static const int min_scnt;
static const int max_scnt;

물론 정적 멤버 필드들은 클래스 외부에도 선언해 주어야 합니다. 특히 정적 상수화 멤버 필드는 상수 값을 설정해 주어야죠.

int Student::last_pn;
const int Student::def_iq=100;
const int Student::min_iq=0;
const int Student::max_iq=200;
const int Student::def_hp=100;
const int Student::min_hp=0;
const int Student::max_hp=200;
const int Student::def_stress=0;
const int Student::min_stress=0;
const int Student::max_stress=100;
const int Student::def_scnt=0;
const int Student::min_scnt=0;
const int Student::max_scnt=5;

현재까지 작성한 프로그램의 코드 내용입니다.

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

class Student
{
    const int pn;//주민번호
    static int last_pn;//가장 최근에 부여한 주민 번호
    string name;//이름
    int iq;//지력
    int hp;//체력
    int stress;//스트레스
    int scnt;//연속으로 공부한 횟수

    //능력치의 디폴트, 최소, 최대값
    static const int def_iq;
    static const int min_iq;
    static const int max_iq;

    static const int def_hp;
    static const int min_hp;
    static const int max_hp;

    static const int def_stress;
    static const int min_stress;
    static const int max_stress;
    static const int def_scnt;
    static const int min_scnt;
    static const int max_scnt;
};
//Student.cpp
#include "Student.h"

int Student::last_pn;
const int Student::def_iq=100;
const int Student::min_iq=0;
const int Student::max_iq=200;
const int Student::def_hp=100;
const int Student::min_hp=0;
const int Student::max_hp=200;
const int Student::def_stress=0;
const int Student::min_stress=0;
const int Student::max_stress=100;
const int Student::def_scnt=0;
const int Student::min_scnt=0;
const int Student::max_scnt=5;
//Program.cpp
#include "Student.h"

int main()
{
    return 0;
}

이제 여러분은 캡슐화할 멤버 멤서드 이름과 입력 매개 변수 목록 및 반환 형식을 결정하세요.

 24. 캡슐화 최종 실습 – 멤버 메서드

이제 시나리오를 보면서 멤버 메서드를 결정하세요. 여기에서는 메서드 이름과 입력 매개 변수 리스트 및 반환 형식까지 결정하세요. 메서드 내부를 구체적으로 결정하는 부분은 테스트 코드 작성 후에 맨 마지막에 할 거예요. 먼저 혼자 해 본 후에 비교해 보세요.

먼저 다른 형식에서 접근 가능하게 접근 지정자 public:을 명시하세요.

public:

생성할 때 이름을 입력받으므로 이를 반영하여 생성자 메서드를 결정하세요.

    Student(string name);//생성자

“공부하다.”, “강의받다.”, “잠자다.”, “휴식하다.”, “음료마시다.”, “노래하다.” 기능에 맞게 메서드 명을 결정하세요. 입력 매개 변수와 반환 형식은 특별히 전달할 것이 없네요.

    void Study();//공부하다.
    void ListenLecture();//강의받다.
    void Sleep();//잠자다.
    void Relax();//휴식하다.
    void Drink();//음료마시다.
    void Sing();//노래하다.

접근자 메서드는 Get으로 시작하고 반환할 데이터에 맞게 메서드 이름을 정하세요. 그리고 접근자는 개체의 상태를 변경하지 않으므로 const 멤버 메서드로 정하세요. 반환 형식은 목적에 맞게 정하세요.

    string GetName()const;//이름 접근자
    int GetPN()const;//주민번호 접근자
    int GetIQ()const;//지력 접근자
    int GetHP()const;//체력 접근자
    int GetStress()const;//스트레스 접근자

여기에서는 구체적인 구현을 들어가지 않았기 때문에 접근 지정이 private 인 멤버 메서드는 없습니다. 하지만 뒤에서 구체적인 구현을 하면서 필요한 것들은 private으로 접근 지정할 거예요.

소스 코드에도 메서드를 추가하고 컴파일 오류가 발생하지 않게 하세요.

먼저 생성자에서는 비정적 상수화 멤버 필드를 초기화를 해야 컴파일 오류가 발생하지 않습니다.

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

접근자 메서드들은 목적에 맞게 적절한 값을 반환하세요. 다음은 멤버 메서드를 추가한 후에 전체 소스 코드 내용이예요.

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

class Student
{
    const int pn;//주민번호
    static int last_pn;//가장 최근에 부여한 주민 번호
    string name;//이름
    int iq;//지력
    int hp;//체력
    int stress;//스트레스
    int scnt;//연속으로 공부한 횟수

    //능력치의 디폴트, 최소, 최대값
    static const int def_iq;
    static const int min_iq;
    static const int max_iq;

    static const int def_hp;
    static const int min_hp;
    static const int max_hp;

    static const int def_stress;
    static const int min_stress;
    static const int max_stress;

    static const int def_scnt;
    static const int min_scnt;
    static const int max_scnt;
public:
    Student(string name);//생성자
    void Study();//공부하다.
    void ListenLecture();//강의받다.
    void Sleep();//잠자다.
    void Relax();//휴식하다.
    void Drink();//음료마시다.
    void Sing();//노래하다.
    string GetName()const;//이름 접근자
    int GetPN()const;//주민번호 접근자
    int GetIQ()const;//지력 접근자
    int GetHP()const;//체력 접근자
    int GetStress()const;//스트레스 접근자
};
//Student.cpp
#include "Student.h"

int Student::last_pn;
const int Student::def_iq=100;
const int Student::min_iq=0;
const int Student::max_iq=200;
const int Student::def_hp=100;
const int Student::min_hp=0;
const int Student::max_hp=200;
const int Student::def_stress=0;
const int Student::min_stress=0;
const int Student::max_stress=100;
const int Student::def_scnt=0;
const int Student::min_scnt=0;
const int Student::max_scnt=5;

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

void Student::Study()
{
}

void Student::ListenLecture()
{
}

void Student::Sleep()
{
}

void Student::Relax()
{
}

void Student::Drink()
{
}

void Student::Sing()
{
}

string Student::GetName()const
{
    return name;
}

int Student::GetPN()const
{
    return pn;
}

int Student::GetIQ()const
{
    return iq;
}

int Student::GetHP()const
{
    return hp;
}

int Student::GetStress()const
{
    return stress;
}
//Program.cpp
#include "Student.h"

int main()
{
    return 0;
}

 25. 캡슐화 최종 실습 – 테스트 코드 작성

이제 시나리오를 보면서 테스트 코드를 작성하세요.

많은 곳에서 구현한 후에 테스트를 수행합니다. 그리고 테스트 코드도 테스트를 수행하기 바로 전에 작성하죠. 하지만 소프트웨어 테스트는 많은 신경을 써도 충분하지 않아 배포 후에 버그를 발견할 때도 많습니다.

소프트웨어 개발에서 잘못 작성한 것은 빨리 발견할수록 전체 비용을 줄어듭니다. 이러한 이유로 많은 연구에서 설계가 끝나면 구현 작업과 함께 시작할 것을 권하고 있습니다. 그리고 구현한 것을 빠르게 테스트를 할 수 있게 원하는 결과가 나왔는지 빠르게 판단할 수 있는 다양한 기법을 사용하고 있습니다.

여기에서는 테스트를 빠르게 판단할 수 있는 코드 작성에 관해서는 다루지 않습니다.

여러분께서 어떻게 하면 학생 클래스를 잘 정의하였는지 테스트 할 수 있는 코드를 작성한 후에 비교해 보세요. 여기에서 작성한 테스트 코드는 모든 것을 테스트 할 수 있게 작성하지 않았습니다. 그리고 빠르게 버그를 판단할 수 있게 작성한 것이 아니므로 보다 나은 테스트 방법에 관해 고민해 보세요.

먼저 테스트에서 학생 정보를 출력하여 상태를 확인할 수 있게 학생 정보를 출력하는 기능을 구현하세요.

void ViewStuInfo(Student *stu)
{
    cout<<"주민 번호:"<<stu->GetPN()<<" 이름:"<<stu->GetName()<<endl;
    cout<<"지력:"<<stu->GetIQ()<<" 체력:"<<stu->GetHP()<<" 스트레스:"<<stu->GetStress()<<endl;
}

학생의 주민번호가 순차적으로 부여하는지 확인하는 기능도 필요하겠죠.

void TestPN()
{
    Student *stu;
    cout<<"10명의 학생 생성 후 소멸(순차적으로 주민 번호 부여 테스트)"<<endl;

    for(int i = 0; i<10;i++)
    {
        stu = new Student("테스트");
        ViewStuInfo(stu);
        delete stu;
    }
    cout<<endl;
}

이제 기능에 따라 학생 상태를 시나리오에 맞게 바뀌는지 확인하는 코드를 작성하세요. 여기에서는 간단하게 구현하였습니다. 모든 테스트를 할 수 있는 코드나 버그를 빠르게 확인할 수 있게 작성하려면 무엇을 변경하고 추가해야 할 지 생각해 보세요.

void TestStudy()
{
    Student *stu = new Student("홍길동");
    ViewStuInfo(stu);

    cout<<"공부하다 8회 실시"<<endl;
    for(int i = 0; i<8;i++)
    {
        stu->Study();
        ViewStuInfo(stu);       
    }
    delete stu;
}

void TestEtc()
{
    Student *stu = new Student("홍길동");
    ViewStuInfo(stu);

    cout<<"공부하다 3회 실시"<<endl;
    for(int i = 0; i<3;i++)
    {
        stu->Study();
        ViewStuInfo(stu);  
    }
    cout<<"강의받다 3회 실시"<<endl;
    for(int i = 0; i<3;i++)
    {
        stu->ListenLecture();
        ViewStuInfo(stu);    
    }
    cout<<"공부하다 1회 실시"<<endl;
    stu->Study();
    ViewStuInfo(stu);
    //이하 생략
    delete stu;
}

다음은 이제까지 작성한 전체 코드 내용입니다.

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

class Student
{
    const int pn;//주민번호
    static int last_pn;//가장 최근에 부여한 주민 번호
    string name;//이름
    int iq;//지력
    int hp;//체력
    int stress;//스트레스
    int scnt;//연속으로 공부한 횟수

    //능력치의 디폴트, 최소, 최대값
    static const int def_iq;
    static const int min_iq;
    static const int max_iq;
    static const int def_hp;
    static const int min_hp;
    static const int max_hp;
    static const int def_stress;
    static const int min_stress;
    static const int max_stress;
    static const int def_scnt;
    static const int min_scnt;
    static const int max_scnt;
public:
    Student(string name);//생성자
    void Study();//공부하다.
    void ListenLecture();//강의받다.
    void Sleep();//잠자다.
    void Relax();//휴식하다.
    void Drink();//음료마시다.
    void Sing();//노래하다.
    string GetName()const;//이름 접근자
    int GetPN()const;//주민번호 접근자
    int GetIQ()const;//지력 접근자
    int GetHP()const;//체력 접근자
    int GetStress()const;//스트레스 접근자
};
//Student.cpp
#include "Student.h"

int Student::last_pn;
const int Student::def_iq=100;
const int Student::min_iq=0;
const int Student::max_iq=200;
const int Student::def_hp=100;
const int Student::min_hp=0;
const int Student::max_hp=200;
const int Student::def_stress=0;
const int Student::min_stress=0;
const int Student::max_stress=100;
const int Student::def_scnt=0;
const int Student::min_scnt=0;
const int Student::max_scnt=5;

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

void Student::Study()
{
}

void Student::ListenLecture()
{
}

void Student::Sleep()
{
}

void Student::Relax()
{
}

void Student::Drink()
{
}

void Student::Sing()
{
}

string Student::GetName()const
{
    return name;
}

int Student::GetPN()const
{
    return pn;
}

int Student::GetIQ()const
{
    return iq;
}

int Student::GetHP()const
{
    return hp;
}

int Student::GetStress()const
{
    return stress;
}
//Program.cpp
#include "Student.h"
#include <iostream>
using namespace std;

void ViewStuInfo(Student *stu);//학생 정보 출력
void TestPN();//순차적으로 주민 번호 부여 테스트
void TestStudy();//공부하다 테스트
void TestEtc();//나머지 테스트

int main()
{
    TestPN();//순차적으로 주민 번호 부여 테스트
    TestStudy();//공부하다 테스트
    TestEtc();//나머지 테스트
    return 0;
}

void ViewStuInfo(Student *stu)
{
    cout<<"주민 번호:"<<stu->GetPN()<<" 이름:"<<stu->GetName()<<endl;
    cout<<"지력:"<<stu->GetIQ()<<" 체력:"<<stu->GetHP()<<" 스트레스:"<<stu->GetStress()<<endl;
}

void TestPN()
{
    Student *stu;
    cout<<"10명의 학생 생성 후 소멸(순차적으로 주민 번호 부여 테스트)"<<endl;
    for(int i = 0; i<10;i++)
    {
        stu = new Student("테스트");
        ViewStuInfo(stu);
        delete stu;
    }
    cout<<endl;
}

void TestStudy()
{
    Student *stu = new Student("홍길동");
    ViewStuInfo(stu);
    cout<<"공부하다 8회 실시"<<endl;
    for(int i = 0; i<8;i++)
    {
        stu->Study();
        ViewStuInfo(stu);
    }
    delete stu;
}

void TestEtc()
{
    Student *stu = new Student("홍길동");
    ViewStuInfo(stu);
    cout<<"공부하다 3회 실시"<<endl;
    for(int i = 0; i<3;i++)
    {
        stu->Study();
        ViewStuInfo(stu);       
    }
    cout<<"강의받다 3회 실시"<<endl;
    for(int i = 0; i<3;i++)
    {
        stu->ListenLecture();
        ViewStuInfo(stu);    
    }
    cout<<"공부하다 1회 실시"<<endl;
    stu->Study();
    ViewStuInfo(stu);
    //이하 생략
    delete stu;
}