ग्रेड कैलकुलेटर (एक पिछले से नया OOP संस्करण)
मैं सोचने का एक OOP तरीका विकसित करने की कोशिश कर रहा हूं। मैं उम्मीद कर रहा था कि कोई व्यक्ति मेरे ग्रेड कैलकुलेटर ओओपी कार्यक्रम की समीक्षा करने के लिए अपने मूल्यवान समय में से कुछ को छोड़ने के लिए पर्याप्त होगा। हमेशा की तरह, मैं जानना चाहता हूं कि मैंने क्या अच्छा किया है, मुझे किस पर सुधार करना चाहिए, और किसी भी सुझाव पर कि मैं कैसे सुधार सकता हूं? वैसे, मेरे पास एक वर्ग है जिसे क्लास कहा जाता है। मुझे शायद इसे "cls" के साथ उपसर्ग करना चाहिए ताकि भ्रमित न हो। इस कार्यक्रम के रूप में माना जाता है कि प्रवेश किया जाना है, मैंने त्रुटि की जाँच नहीं की है। इस कार्यक्रम का उद्देश्य 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();
}
जवाब
आपके कार्यक्रम को बेहतर बनाने में आपकी मदद करने के लिए यहां कुछ चीजें दी गई हैं।
डेटा ऑपरेशन के साथ I / O को न मिलाएं
आम तौर पर बोलना std::getline
और std::cout
एक डेटा वर्ग जैसे कि Class
एक अच्छा विचार नहीं है। इससे कक्षा का पुन: उपयोग करना कठिन हो जाता है। बेहतर अभ्यास (डेटा रखने के लिए है Student
, Class
आदि) उन से इनपुट हो रहा से अलग करते हैं। मॉडल-व्यू-नियंत्रक डिजाइन पैटर्न अक्सर इस तरह के कार्यक्रमों के लिए उपयोगी है। इस उत्तरConsoleMenu
में कक्षा जैसी किसी चीज़ का उपयोग करने पर विचार करें ।
जहां व्यावहारिक हो वहां मूवमेंट शब्द का प्रयोग करें
में AddStudent
समारोह, हम इस लाइन है:
students.push_back({ name, scoreGot });
बेहतर होगा उपयोग करने के लिए emplace_backजो संकलक को बताता है कि इसे बनाने और कॉपी करने की आवश्यकता नहीं है, लेकिन यह जगह में ऑब्जेक्ट का निर्माण करने के लिए सुरक्षित है।
श्रेणी इंटरफ़ेस को रीथिंक करें
Class
वर्ग इस सदस्य समारोह है:
std::vector<Student>& accessStudents() { return students; }
यह विचार अच्छा नहीं है। यह एक आंतरिक वर्ग के सदस्य का संदर्भ देता है। सोचें कि यदि Class
उदाहरण हटा दिया जाए तो क्या होता है, लेकिन कुछ बाहरी संस्था अभी भी डेटा का संदर्भ ले रही है जो अब मौजूद नहीं है। इसका उपयोग किया जाने वाला एकमात्र स्थान भीतर है GradeCalculator::averageGrade()
और GradeCalculator::DislayResult()
इसलिए यह एक मजबूत संकेतक है कि क्लास इंटरफ़ेस में कुछ सही नहीं है। मेरा सुझाव है कि इस averageGrade()
समारोह को एक Class
सदस्य समारोह बनाना चाहिए।
समझदार होने पर चूक का उपयोग करें
Student
निर्माता अनिवार्य रूप से होता है जो संकलक द्वारा उत्पन्न की है कि के समान है। त्रुटि की संभावना को कम करने के लिए, इसे केवल समाप्त किया जा सकता है।
उपयोगकर्ता के बारे में सोचो
इनायत कार्यक्रम से बाहर निकलने का कोई स्पष्ट तरीका नहीं है। मैं उसके लिए एक मेनू आइटम जोड़ने का सुझाव दूंगा। इसके अलावा, संभावना है कि वास्तव में कार्यक्रम का उपयोग करने वाला कोई भी छात्रों की पूरी कक्षा में प्रवेश करना चाहता है और फिर पूरी कक्षा के लिए अंकों की गणना करेगा। बार-बार "1. छात्र जोड़ें ..." का चयन करना थोड़ा कठिन है। बेहतर हो सकता है कि कार्यक्रम में एक खाली नाम या शायद "छोड़ दिया" दर्ज होने तक इनपुट इकट्ठा किया जाए, और फिर स्वचालित रूप से स्कोर दिखाए जाएं। बेहतर अभी भी एक पाठ फ़ाइल से इनपुट की अनुमति होगी।