演習:オブジェクト指向設計
[これまでの]35[課]で、[私たちは]C++[のあらゆる側面]を学びました。
[今]、[まさに][総合的に活用する][時]です。
[この授業では]、[私たちは][完全な学生管理システム]を[要件定義から]code[実装]まで[一通り作り上げ]、[本格的なソフトウェア開発を体験]します。
1. プロジェクト[要件分析]
(1) 1.1 [機能要件]
[私たちが実現しようとしている学生管理システム]は、[以下の機能を備えています]:
| [機能モジュール] | [具体的な機能] |
|---|---|
| [学生管理] | [追加]、[削除]、[編集]、[学生の検索] |
| [成績管理] | [成績入力]、[平均点の算出]、[順位] |
| [データの永続化] | [ファイルへの保存]、[ファイルからの読み込み] |
| [ユーザーインターフェース] | [メニュー駆動型のコンソールインターフェース] |
(2) 1.2 クラス[の設計]
[要件に基づき]、[以下の]クラスを設計する必要があります:
Student()
↑
UndergraduateStudent()
GraduateStudent()
Course()
Grade()
ManagementSystem()
- vector<Student*> students
- vectorCourse courses
2. [基本バージョンの実装]
(1) 2.1 [学生]クラス[設計]
例:[学生]クラス[基礎版] (難易度 ⭐⭐)
#include iostream
#include string
#include vector
// ...
class Student {
protected:
std::string id; // ...
std::string name; // ...
int age; // ...
std::string major; // ...
public:
// ...
Student(const std::string& id, const std::string& name, int age, const std::string& major)
: id(id), name(name), age(age), major(major) {}
//:
virtual void display() const {
std::cout << ":" << id << std::endl;
std::cout << ":" << name << std::endl;
std::cout << ":" << age << std::endl;
std::cout << ":" << major << std::endl;
}
// ...
virtual ~Student() {}
// Getter
std::string getId() const { return id; }
std::string getName() const { return name; }
};
// ...
class UndergraduateStudent : public Student {
private:
int year; // (1-4)
public:
UndergraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, int year)
: Student(id, name, age, major), year(year) {}
void display() const override {
Student::display();
std::cout << ":" << year << "..." << std::endl;
std::cout << ":" << std::endl;
}
};
// ...
class GraduateStudent : public Student {
private:
std::string advisor; // ...
public:
GraduateStudent(const std::string& id, const std::string& name,
int age, const std::string& major, const std::string& advisor)
: Student(id, name, age, major), advisor(advisor) {}
void display() const override {
Student::display();
std::cout << ":" << advisor << std::endl;
std::cout << ":" << std::endl;
}
};
(2) 2.2 [管理システム]クラス
例:[管理システム ベーシック版] (難易度 ⭐⭐⭐)
▶ サンプル 1: STLコンテナ[使用] (難易度 ⭐)
class ManagementSystem {
private:
std::vector<Student*> students; // ()
public:
// ...
void addStudent(Student* student) {
students.push_back(student);
std::cout << "!" << std::endl;
}
// ...
Student* findStudent(const std::string& id) {
for (auto s : students) {
if (s->getId() == id) {
return s;
}
}
return nullptr;
}
// ...
void displayAll() const {
if (students.empty()) {
std::cout << "..." << std::endl;
return;
}
for (auto s : students) {
s->display();
std::cout << "-------------------" << std::endl;
}
}
//:
~ManagementSystem() {
for (auto s : students) {
delete s;
}
}
};
// ...
int main() {
ManagementSystem sys;
// ...
sys.addStudent(new UndergraduateStudent("001", "...", 20, "...", 3));
sys.addStudent(new GraduateStudent("002", "...", 24, "...", "..."));
// ...
sys.displayAll();
return 0;
}
[実行結果]:
-------------------:002::24:::
-------------------
3. [完全版の実装]
(1) 3.1 [機能の追加]
[現在]、[システムにさらなる機能を追加しています]:
| [機能] | [実装方法] |
|---|---|
| [学生を削除] | [学籍番号で削除] |
| [情報の変更] | [学籍番号で検索]、[変更] |
| [成績管理] | [成績の追加]クラス |
| ファイル[保存] | [用] ofstream [書]ファイル |
| ファイル[読み込み] | ifstream を使用して [ファイル]を読み込む |
(2) 3.2 [成績]クラス[設計]
// ...
### (3) ▶ 2:(⭐)
class Grade {
private:
std::string courseId; // ID
std::string courseName; // ...
double score; // points
public:
Grade(const std::string& courseId, const std::string& courseName, double score)
: courseId(courseId), courseName(courseName), score(score) {}
void display() const {
std::cout << courseName << ":" << score << "points" << std::endl;
}
double getScore() const { return score; }
};
// ...
class Student {
// ... ...
std::vectorGrade grades; // ...
public:
void addGrade(const Grade& grade) {
grades.push_back(grade);
}
void displayGrades() const {
if (grades.empty()) {
std::cout << "..." << std::endl;
return;
}
std::cout << name << ":" << std::endl;
for (const auto& g : grades) {
g.display();
}
}
double getAverage() const {
if (grades.empty()) return 0.0;
double sum = 0;
for (const auto& g : grades) {
sum += g.getScore();
}
return sum / grades.size();
}
};
(3) 3.3 ファイル[操作]
[学生情報を保存するファイル:]
void saveToFile(const std::string& filename) {
std::ofstream file(filename);
if (!file) {
std::cout << "..." << std::endl;
return;
}
for (auto s : students) {
file << s->getId() << ","
<< s->getName() << ","
<< s->getAge() << std::endl;
}
file.close();
std::cout << "!" << std::endl;
}
[ファイルから]読み込み:
void loadFromFile(const std::string& filename) {
std::ifstream file(filename);
if (!file) {
std::cout << "..." << std::endl;
return;
}
std::string id, name, ageStr;
while (std::getline(file, id, ',')) {
std::getline(file, name, ',');
std::getline(file, ageStr);
int age = std::stoi(ageStr);
// (,points/)
students.push_back(new UndergraduateStudent(id, name, age, "...", 1));
}
file.close();
std::cout << "!" << std::endl;
}
4. [メニュー画面の実装]
(1) 4.1 [メインメニュー]
void showMenu() {
std::cout << "\n===== =====" << std::endl;
std::cout << "1." << std::endl;
std::cout << "2." << std::endl;
std::cout << "3." << std::endl;
std::cout << "4." << std::endl;
std::cout << "5." << std::endl;
std::cout << "6." << std::endl;
std::cout << "0." << std::endl;
std::cout << "========================" << std::endl;
std::cout << ":";
}
int main() {
ManagementSystem sys;
int choice;
do {
showMenu();
std::cin >> choice;
switch (choice) {
case 1:
// ...
break;
case 2:
// ...
break;
case 3:
sys.displayAll();
break;
case 0:
std::cout << "!" << std::endl;
break;
default:
std::cout << "..." << std::endl;
}
} while (choice != 0);
return 0;
}
5. プロジェクト[拡張提案]
(1) 5.1 [機能拡張]
| [機能] | [難易度] | [説明] |
|---|---|---|
| [成績統計] | ⭐⭐ | [平均点の算出]、[順位] |
| [データ検証] | ⭐⭐ | [チェック]入力[有効性] |
| 例外処理 | ⭐⭐⭐ | [用] try-catch [処理]エラー |
| [グラフィカルユーザーインターフェース] | ⭐⭐⭐⭐ | [Qt]または[wxWidgets]を使用 |
| [データベース] | ⭐⭐⭐⭐ | [SQLiteまたは]MySQL |
(2) 5.2 コードの最適化
| 最適化[点] | [説明] |
|---|---|
| スマートポインタ | [使用] unique_ptr [メモリ管理] |
| const[正しさ] | [可能な限り使用する] const |
| 例外処理 | [用] try-catch [処理]fileerror |
| 演算子のオーバーロード | オーバーロード << [出力用] |
❓ よくある質問
Q:[なぜ]ポインタ[を使って学生を格納する]のか? A:[ポリモーフィズムを実現するため]。[もし]
vectorStudentを使えば、[オブジェクトのスライシングが]発生し、[基底クラスのメソッドしか呼び出せなくなる]。
Q:メモリリーク[どうすればいいですか]? A:スマートポインタ(
unique_ptr)を使ってメモリを[自動管理]すれば、[手動で]deleteする必要はありません。
Q:ファイル形式はどのように設計すればよいですか? A:[以下の形式が利用可能です]: - CSV形式:[シンプル]ですが、[機能に制限があります] - JSON形式:[機能豊富]ですが、[サードパーティ製ライブラリが必要です] - [バイナリ形式]:[効率が良い]ですが、[人間が読み取れません]
wstring + wcout [を使用する] - [サードパーティ製ライブラリ]([例:]iconv)[を使用する] - [ピンイン]または[英語]のみを保存する📖 まとめ
| [知識ポイント] | [要点] |
|---|---|
| class[設計] | 基底クラス + 派生クラス,[体現]継承 |
| 多態性 | [ポインタ/参照]による仮想関数の呼び出し |
| ファイル[操作] | ofstream [書き込み],ifstream [読み取り] |
| メモリ[管理] | デストラクタ[解放]メモリ([または]スマートポインタ) |
| [メニュー画面] | do-while + switch |
[学習のヒント]:
- [この]プロジェクト[は総合演習です]。[必ず自分で一度コードを書いてみてください]
- [まず基本機能を実装し]、[その後、段階的に機能を拡張する]
- [問題に直面したら、まず資料を調べる]、[問題解決能力を養う]
📝 練習問題
-
初心者(難易度 ⭐):[Bookクラス([書名]、[著者]、[価格])を定義し、3つのオブジェクトを[作成]して、[それらの属性]を出力する。
-
**中級(難易度 ⭐⭐):[継承]体系を実装する:Shape(基底クラス、純粋仮想関数 area())→ Circle [および] Rectangle の派生クラス。[多態性]を利用して area を呼び出す。
-
**上級(難易度 ⭐⭐⭐):[「オブザーバーパターン」を実装する]:Subjectクラスは[オブザーバーのリストを保持し]、オブザーバーは[抽象]基底クラスである。[Subjectの状態が変化した際、すべての]オブザーバーに通知する。
- [本節では] オブジェクト指向プログラミング(OOP)の [核心となる概念] について解説します
- [習得すれば、関連する] C++ プログラムを作成できるようになる
フェーズ5 [終了]![次へ]:フェーズ6(STL[上級])



