この記事では、C++を使用して成績管理システムを設計・実装する方法について説明します。以下のセクションで、クラス設計、コード例、およびいくつかの問題に対する回答を提供します。
1. システム概要
成績管理システムは、学生の成績を入力、出力、並べ替え、統計情報を計算する機能を備えています。
1.1 主なクラス設計
主なクラスである GradeManager には、次のメソッドが含まれます:
addGrades(): 成績を追加します。displayGrades(): 現在の成績を表示します。sortGrades(bool ascending): 成績を昇順または降順に並べ替えます。getMinGrade(): 最低点を返します。getMaxGrade(): 最高点を返します。getAverageGrade(): 平均点を計算します。printStats(): 各スコア範囲の人数と比率を表示します。
2. コード例
2.1 ヘッダーファイル: GradeManager.hpp
#pragma once
#include <string>
#include <vector>
#include <array>
class GradeManager {
public:
GradeManager(const std::string& subjectName);
void addGrades(int count);
void displayGrades() const;
void sortGrades(bool ascending = false);
int getMinGrade() const;
int getMaxGrade() const;
double getAverageGrade() const;
void printStats();
private:
void calculateStats();
std::string subject;
std::vector<int> scores;
std::array<int, 5> scoreCounts;
std::array<double, 5> scoreRates;
bool isDataUpdated;
};
2.2 実装ファイル: GradeManager.cpp
#include "GradeManager.hpp"
#include <iostream>
#include <algorithm>
#include <numeric>
GradeManager::GradeManager(const std::string& subjectName)
: subject{subjectName}, isDataUpdated{true} {
scoreCounts.fill(0);
scoreRates.fill(0.0);
}
void GradeManager::addGrades(int count) {
if (count <= 0) return;
int tempScore;
for (int i = 0; i < count; ++i) {
std::cin >> tempScore;
if (tempScore < 0 || tempScore > 100) continue;
scores.push_back(tempScore);
}
isDataUpdated = true;
}
void GradeManager::displayGrades() const {
for (auto s : scores) std::cout << s << ' ';
std::cout << '\n';
}
void GradeManager::sortGrades(bool ascending) {
if (ascending)
std::sort(scores.begin(), scores.end());
else
std::sort(scores.begin(), scores.end(), std::greater<int>());
}
int GradeManager::getMinGrade() const {
if (scores.empty()) return -1;
return *std::min_element(scores.begin(), scores.end());
}
int GradeManager::getMaxGrade() const {
if (scores.empty()) return -1;
return *std::max_element(scores.begin(), scores.end());
}
double GradeManager::getAverageGrade() const {
if (scores.empty()) return 0.0;
return std::accumulate(scores.begin(), scores.end(), 0.0) / scores.size();
}
void GradeManager::printStats() {
if (isDataUpdated) calculateStats();
std::cout << "教科名: " << subject << "\n";
std::cout << "平均点: " << getAverageGrade() << "\n";
std::cout << "最高点: " << getMaxGrade() << "\n";
std::cout << "最低点: " << getMinGrade() << "\n";
const std::array<std::string, 5> ranges{
"[0,60)", "[60,70)", "[70,80)", "[80,90)", "[90,100]"};
for (size_t i = 0; i < ranges.size(); ++i)
std::cout << ranges[i] << ": " << scoreCounts[i]
<< "人 (" << scoreRates[i] * 100 << "%)\n";
}
void GradeManager::calculateStats() {
if (scores.empty()) return;
scoreCounts.fill(0);
scoreRates.fill(0.0);
for (auto s : scores) {
if (s < 60) ++scoreCounts[0];
else if (s < 70) ++scoreCounts[1];
else if (s < 80) ++scoreCounts[2];
else if (s < 90) ++scoreCounts[3];
else ++scoreCounts[4];
}
for (size_t i = 0; i < scoreRates.size(); ++i)
scoreRates[i] = static_cast<double>(scoreCounts[i]) / scores.size();
isDataUpdated = false;
}
2.3 テストコード: main.cpp
#include "GradeManager.hpp"
#include <iostream>
int main() {
GradeManager manager("数学");
std::cout << "成績を入力してください:\n";
manager.addGrades(5);
std::cout << "成績一覧:\n";
manager.displayGrades();
std::cout << "並べ替え後:\n";
manager.sortGrades();
manager.displayGrades();
std::cout << "統計情報:\n";
manager.printStats();
}
3. 問題とその解決策
以下は、実装中に考えられるいくつかの問題とその回答です。
3.1 問題: スコア範囲の設定
質問: スコア範囲をどのように設定すればよいですか?
回答: スコア範囲は、std::array<int, 5> を使用して定義できます。それぞれの範囲に対応するインデックスを持つことで、効率的にデータを処理できます。
3.2 問題: データ更新時の通知
質問: データが更新されたときに、統計情報を再計算させる必要がありますか?
回答: はい。フラグ (isDataUpdated) を使用して、データが変更された場合にのみ再計算を行います。
3.3 問題: 中央値の計算
質問: 中央値を計算する方法はありますか?
回答: 次のように、中央値を計算する関数を追加できます:
double GradeManager::getMedian() const {
if (scores.empty()) return -1.0;
std::vector<int> sortedScores = scores;
std::sort(sortedScores.begin(), sortedScores.end());
size_t mid = sortedScores.size() / 2;
if (sortedScores.size() % 2 == 0)
return (sortedScores[mid - 1] + sortedScores[mid]) / 2.0;
return sortedScores[mid];
}