I'm trying to develop an OOP way of thinking. I was hoping someone would be kind enough to spare some of their valuable time to review my Grade Calculator OOP program. As always, I'd like to know what I've done well, what I should improve upon, and any suggestions on how I could perhaps improve what I have? By the way, I have a class called Class. I probably should prefix it with "cls" so as not to confuse. Treat this program as is supposed to be entered, I haven't error checked it. The point of this program is to develop in OOP.
// Task 1.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
class TestPaper
{
public:
int m_scoreOutOf;
bool checkBoundary(int value, int boundary) {
if (value < 0 || value > boundary) {
std::cout << "Score must be between " << " 0 and " << boundary << ". Please try again.\n";
return false;
}
return true;
}
};
class Student {
private:
std::string m_name;
int m_scoreGot;
public:
Student(std::string name, int scoreGot)
:m_name(name), m_scoreGot(scoreGot){}
std::string getName() const { return m_name; }
int getScoreGot() const { return m_scoreGot; }
};
class Class {
private:
std::vector<Student>students;
public:
void AddStudent(TestPaper& testPaper) {
std::string name = "";
int scoreGot = 0;
std::cout << "Enter student name: ";
std::getline(std::cin >> std::ws, name);
do
{
std::cout << "\nWhat did " << name << " score?\nEnter a score between 0 and "
<< testPaper.m_scoreOutOf << ": ";
std::cin >> scoreGot;
} while (testPaper.checkBoundary(scoreGot, testPaper.m_scoreOutOf) == false);
students.push_back({ name, scoreGot });
}
std::vector<Student>& accessStudents() { return students; }
};
class GradeCalculator {
TestPaper m_testPaper;
Class m_ClassOfStudents;
public:
GradeCalculator(TestPaper testPaper, Class classOfStudents) :m_testPaper(testPaper), m_ClassOfStudents(classOfStudents) {}
void DisplayMenu() {
std::cout << "\n1. Add student and their grade\n";
std::cout << "2. Calculate class score\n";
std::cout << "3. Modify testpaper (haven't implemented this yet)\n";
}
double averageGrade() {
auto sum = std::transform_reduce(m_ClassOfStudents.accessStudents().begin(), m_ClassOfStudents.accessStudents().end(), 0.0, std::plus<>(),
[&](auto& student) { return calculateGradePercentage(student); });
return sum / m_ClassOfStudents.accessStudents().size();
}
double calculateGradePercentage(Student &student)
{
return static_cast<double>(student.getScoreGot()) / static_cast<double>(m_testPaper.m_scoreOutOf) * 100;
}
void DisplayResult() {
for (auto& student : m_ClassOfStudents.accessStudents()) {
std::cout << "Percentage scores are: \n";
std::cout << student.getName() << ": " << calculateGradePercentage(student) << "%\n";
}
std::cout << "Average grade perecentage: " << averageGrade() << "%\n";
}
void runProgram() {
int menuChoice = 0;
while (true)
{
DisplayMenu();
std::cout << "\nEnter a choice from the menu: ";
std::cin >> menuChoice;
switch (menuChoice)
{
case 1:
m_ClassOfStudents.AddStudent(m_testPaper);
break;
case 2:
DisplayResult();
break;
default:
std::cout << "Invalid choice!\n";
}
}
}
};
int main()
{
TestPaper testPaper({ 20 });
Class classOfStudents;
GradeCalculator calculator(testPaper, classOfStudents);
calculator.runProgram();
}