요약 - 학생 기록 시스템
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 39번째.
캡슐화 지식을 실제로 적용해 볼 시간입니다! 이 챌린지에서는 접근 지정자, 정보 은닉, 중첩 클래스의 적절한 사용을 보여주는 학생 기록 시스템(Student Records System)을 구축하게 됩니다.
여러분의 시스템은 다음과 같은 캡슐화 원칙을 사용하여 학생 데이터를 관리합니다:
- 성적 및 학생 ID와 같은 민감한 정보를 보호하기 위한 Private 데이터 멤버
- getter 및 제어된 setter를 포함한 Public 인터페이스
- 개별 과목 성적을 나타내며, 이 구현 세부 사항을 학생 클래스 내에 포함시키는 중첩 클래스
구현할 구조는 다음과 같습니다:
class Student {
public:
class Grade { // 과목 성적을 위한 중첩 클래스
// ...
};
// 학생 데이터와 상호작용하기 위한 Public 인터페이스
private:
std::string name;
int studentId;
// 성적 컬렉션
};이 챌린지는 적절한 접근 수준 선택, 깔끔한 인터페이스 뒤로 구현 세부 사항 숨기기, 관련 유형을 구성하기 위한 중첩 클래스 사용 등 이번 장의 모든 내용을 결합합니다. 무엇을 공개하고 무엇을 숨겨야 할지 신중하게 생각해보세요.
챌린지
쉬움캡슐화에 대해 배운 모든 내용을 하나로 모으는 학생 기록 시스템(Student Records System)을 구축해 보겠습니다. 학생 데이터가 적절하게 보호되고, 성적이 중첩 클래스를 통해 관리되며, 모든 상호 작용이 깔끔한 퍼블릭 인터페이스를 통해 이루어지는 시스템을 만들 것입니다.
코드를 정리하기 위해 두 개의 파일을 생성합니다:
Student.h: 중첩된Grade클래스를 사용하여 적절한 캡슐화를 보여주는Student클래스를 정의합니다.Student의 public 섹션에 선언된 중첩Grade클래스는 과목 이름(string)과 점수(double)를 저장해야 합니다. 두 값을 모두 받는 생성자를 만들고, 데이터에 접근하기 위한getCourseName()및getScore()메서드를 제공하세요.Grade클래스는 데이터를 private으로 유지합니다.Student내부에 중첩되어 있더라도 자체적인 캡슐화를 유지해야 합니다.Student클래스는 학생의 이름(string), 학생 ID(int), 그리고Grade포인터 컬렉션을 위한 private 멤버를 가져야 합니다. 다음을 제공하세요:- 이름과 학생 ID를 받는 생성자
- 게터
getName()및getStudentId()(둘 다 const) - 새로운
Grade를 생성하고 학생의 기록에 추가하는addGrade(const std::string& course, double score)메서드 (점수가 0에서 100 사이인 경우에만 추가) - 모든 성적의 평균을 계산하여 반환하거나, 성적이 없는 경우 0.0을 반환하는
getAverageGrade()(const) 메서드 - 학생의 전체 기록을 보여주는
displayRecord()(const) 메서드
소멸자에서 동적으로 할당된 성적들을 정리하는 것을 잊지 말고, 적절한 헤더 가드(header guards)를 포함하세요.
main.cpp: 입력으로부터 학생 이름, 학생 ID, 그리고 세 개의 과목 성적을 읽습니다. 입력 형식은 다섯 줄입니다: 이름, ID, 그리고 과목 이름과 점수가 공백으로 구분된 세 줄 (예:Math 95.5).이름과 ID로
Student객체를 생성하고, 세 개의 성적을 모두 추가한 다음 전체 기록을 표시합니다.displayRecord()의 출력 형식은 다음과 같아야 합니다:Student: <name> (ID: <id>) Grades: <course1>: <score1> <course2>: <score2> <course3>: <score3> Average: <average>
<iomanip>의 std::fixed와 std::setprecision(1)을 사용하여 모든 점수와 평균을 소수점 첫째 자리까지 표시하세요. std::stoi()를 사용하여 ID를 변환하고 std::stod()를 사용하여 점수를 변환하세요.
이 챌린지는 private 데이터 멤버, public 게터, 유효성 검사가 포함된 제어된 세터, 그리고 중첩 클래스를 결합하여 잘 캡슐화된 학생 기록 시스템을 만드는 과정을 다룹니다.
치트 시트
캡슐화는 데이터 보호와 코드 정리를 위해 접근 지정자, 정보 은닉, 중첩 클래스를 결합합니다.
데이터 보호를 위한 접근 지정자
민감한 데이터 멤버에는 private을 사용하고, 인터페이스에는 public을 사용하세요:
class Student {
public:
// 공개 인터페이스 메서드
private:
std::string name;
int studentId;
// 기타 비공개 데이터
};중첩 클래스
중첩 클래스는 클래스 내에서 관련된 타입들을 정리하며, 자체적인 캡슐화를 유지합니다:
class Student {
public:
class Grade { // 중첩 클래스
private:
std::string courseName;
double score;
public:
Grade(const std::string& course, double s)
: courseName(course), score(s) {}
std::string getCourseName() const { return courseName; }
double getScore() const { return score; }
};
private:
std::vector<Grade*> grades;
};유효성 검사를 통한 제어된 접근
메서드는 비공개 멤버를 수정하기 전에 데이터를 검증할 수 있습니다:
void addGrade(const std::string& course, double score) {
if (score >= 0 && score <= 100) {
grades.push_back(new Grade(course, score));
}
}Const 메서드
데이터를 수정하지 않는 메서드는 const로 표시하세요:
std::string getName() const { return name; }
double getAverageGrade() const {
// 평균을 계산하고 반환
}메모리 관리
소멸자에서 동적으로 할당된 객체들을 정리하세요:
~Student() {
for (Grade* grade : grades) {
delete grade;
}
}직접 해보기
#include <iostream>
#include <string>
#include <sstream>
#include "Student.h"
int main() {
// 학생 이름 읽기
std::string name;
std::getline(std::cin, name);
// 학생 ID 읽기
std::string idStr;
std::getline(std::cin, idStr);
int studentId = std::stoi(idStr);
// 세 개의 과목 성적 읽기 (형식: "과목명 점수")
std::string line1, line2, line3;
std::getline(std::cin, line1);
std::getline(std::cin, line2);
std::getline(std::cin, line3);
// TODO: 각 줄을 파싱하여 과목명과 점수 추출
// 점수 문자열을 double로 변환하기 위해 std::stod() 사용
// TODO: 이름과 ID를 사용하여 Student 객체 생성
// TODO: 학생에게 세 개의 성적 모두 추가
// TODO: 전체 학생 기록 표시
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.