まとめ:学生記録システム
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 39/104。
カプセル化の知識を実践に移す時が来ました!このチャレンジでは、アクセス修飾子、情報の隠蔽、および入れ子になったクラスの適切な使用方法を示す学生記録システムを構築します。
あなたのシステムは、以下のカプセル化の原則に従って学生データを管理します。
- 成績や学生IDなどの機密情報を保護するためのプライベートデータメンバ
- ゲッターと制御されたセッターを備えたパブリックインターフェース
- 個々のコースの成績を表すための入れ子になったクラス。この実装の詳細は学生クラス内に保持されます。
実装する構造は以下の通りです:
class Student {
public:
class Grade { // コース成績のための入れ子になったクラス
// ...
};
// 学生データとやり取りするためのパブリックインターフェース
private:
std::string name;
int studentId;
// 成績のコレクション
};このチャレンジは、適切なアクセスレベルの選択、クリーンなインターフェースの背後への実装詳細の隠蔽、関連する型を整理するための入れ子になったクラスの使用など、この章のすべてを組み合わせたものです。何をアクセス可能にし、何を隠したままにするべきか、慎重に考えてください。
チャレンジ
簡単カプセル化について学んだすべてを統合する、学生記録システムを構築しましょう。学生データが適切に保護され、成績がネストされたクラスを通じて管理され、すべてのやり取りがクリーンなパブリックインターフェースを介して行われるシステムを作成します。
コードを整理するために、2つのファイルを作成します:
Student.h: ネストされたGradeクラスを使用して、適切なカプセル化を実証するStudentクラスを定義します。ネストされた
Gradeクラス(Studentのパブリックセクションで宣言)は、コース名(string)とスコア(double)を保持する必要があります。両方の値を受け取るコンストラクタを作成し、データにアクセスするためのgetCourseName()およびgetScore()メソッドを提供してください。Gradeクラスはそのデータをプライベートに保ちます。Studentの内部にネストされていても、独自のカプセル化を維持します。Studentクラスは、学生の名前(string)、学生ID(int)、およびGradeポインタのコレクションのためのプライベートメンバを持つ必要があります。以下を提供してください:- 名前と学生IDを受け取るコンストラクタ
- ゲッター
getName()およびgetStudentId()(両方とも const) - 新しい
Gradeを作成し、学生の記録に追加するメソッドaddGrade(const std::string& course, double score)(スコアが0から100の範囲内である場合のみ追加) - すべての成績の平均を計算して返すメソッド
getAverageGrade()(const)(成績が存在しない場合は 0.0 を返す) - 学生の完全な記録を表示するメソッド
displayRecord()(const)
デストラクタで動的に割り当てられた成績をクリーンアップすること、および適切なヘッダーガードを含めることを忘れないでください。
main.cpp: 入力から学生の名前、学生ID、および3つのコースの成績を読み取ります。入力形式は5行です:名前、ID、そしてコース名とスコアがスペースで区切られた3行(例:Math 95.5)。名前とIDを使用して
Studentを作成し、3つの成績をすべて追加してから、完全な記録を表示します。displayRecord()の出力形式は以下の通りです:Student: <name> (ID: <id>) Grades: <course1>: <score1> <course2>: <score2> <course3>: <score3> Average: <average>
すべてのスコアと平均は、<iomanip> の std::fixed と std::setprecision(1) を使用して小数点以下1桁でフォーマットしてください。IDの変換には std::stoi() を、スコアの変換には std::stod() を使用してください。
このチャレンジは、プライベートデータメンバ、パブリックゲッター、バリデーション付きの制御されたセッター、およびネストされたクラスを組み合わせて、適切にカプセル化された学生記録システムを作成するものです。
チートシート
カプセル化は、アクセス修飾子、情報の隠蔽、および入れ子になったクラスを組み合わせて、データを保護し、コードを整理します。
データ保護のためのアクセス修飾子
機密性の高いデータメンバには 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);
// 3つのコースの成績を読み込む(形式: "CourseName Score")
std::string line1, line2, line3;
std::getline(std::cin, line1);
std::getline(std::cin, line2);
std::getline(std::cin, line3);
// TODO: 各行を解析してコース名とスコアを抽出する
// std::stod() を使用してスコアの文字列を double 型に変換する
// TODO: 名前とIDを使用して Student オブジェクトを作成する
// TODO: 3つすべての成績を学生に追加する
// TODO: 完全な学生の記録を表示する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス