Kalkulator Kelas (Versi OOP Baru dari sebelumnya)
Saya mencoba mengembangkan cara berpikir OOP. Saya berharap seseorang akan berbaik hati meluangkan waktu mereka yang berharga untuk meninjau program OOP Kalkulator Nilai saya. Seperti biasa, saya ingin tahu apa yang telah saya lakukan dengan baik, apa yang harus saya perbaiki, dan saran tentang bagaimana saya mungkin dapat meningkatkan apa yang saya miliki? Ngomong-ngomong, aku punya kelas yang disebut Kelas. Saya mungkin harus mengawalnya dengan "cls" agar tidak membingungkan. Perlakukan program ini sebagaimana mestinya, saya belum memeriksanya dengan kesalahan. Inti dari program ini adalah untuk mengembangkan dalam 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();
}
Jawaban
Berikut beberapa hal untuk membantu Anda meningkatkan program Anda.
Jangan gabungkan I / O dengan operasi data
Secara umum, memiliki std::getline
dan di std::cout
dalam kelas data seperti Class
itu bukanlah ide yang baik. Kelas akan lebih sulit digunakan kembali. Praktek yang lebih baik adalah untuk menjaga data ( Student
, Class
, dll) terpisah dari mendapatkan masukan dari pengguna. The MVC pola desain sering berguna untuk program seperti ini. Pertimbangkan untuk menggunakan sesuatu seperti ConsoleMenu
kelas seperti dalam jawaban ini .
Gunakan semantik bergerak jika praktis
Dalam AddStudent
fungsinya, kami memiliki baris ini:
students.push_back({ name, scoreGot });
Lebih baik menggunakan emplace_backyang memberi tahu kompiler bahwa ia tidak perlu membuat dan menyalin, tetapi aman untuk membuat objek pada tempatnya.
Pikirkan kembali antarmuka kelas
The Class
kelas memiliki fungsi anggota ini:
std::vector<Student>& accessStudents() { return students; }
Ini ide yang buruk. Ini mengembalikan referensi ke anggota kelas internal. Pikirkan apa yang terjadi jika Class
instance dihapus tetapi beberapa entitas eksternal masih menyimpan referensi ke data yang sudah tidak ada lagi. Satu-satunya tempat yang digunakan adalah di dalam GradeCalculator::averageGrade()
dan GradeCalculator::DislayResult()
itu merupakan indikator kuat bahwa ada sesuatu yang tidak beres di antarmuka kelas. Saya sarankan membuat averageGrade()
fungsi menjadi Class
fungsi anggota.
Gunakan default jika memungkinkan
The Student
konstruktor pada dasarnya sama dengan yang seharusnya dihasilkan oleh compiler. Untuk mengurangi kemungkinan kesalahan, itu bisa dihilangkan begitu saja.
Pikirkan tentang pengguna
Tidak ada cara yang jelas untuk keluar dari program dengan baik. Saya sarankan menambahkan item menu untuk itu. Juga, kemungkinan besar siapa pun yang benar-benar menggunakan program ini ingin memasuki seluruh kelas siswa dan kemudian menghitung skor untuk seluruh kelas. Harus berulang kali memilih "1. Tambah siswa ..." agak membosankan. Lebih baik program mengumpulkan masukan sampai nama kosong atau mungkin "keluar" dimasukkan, dan kemudian secara otomatis menampilkan skor. Lebih baik lagi mengizinkan input dari file teks.