简体   繁体   中英

Classes code to determine final grade and average not working

I recently got an assignment that tasks me to create a class which contains private variables and member functions/void functions. Classes have just been introduced to me and my teacher gave me an assignment that I don't really understand. The issue I'm having is that the average and letter grade aren't correctly being outputted as shown below. Everything has to take place within the member functions. Also, am I using the member functions correctly? I've seen online that they are being defined within the class but in my notes I see that they are referenced and treated just like a user defined function. The confusion I'm having is this part of the assignment:

member functions to set each of the member variables to values given as an argument(s) to the function, member functions to retrieve the data from each of the member variables, a void function that calculates the student's weighted average numeric score for the entire course and sets the corresponding member variable, and a void function that calculates the student's final letter grade and sets the corresponding member variable

My code is below:

#include <iostream>
#include <cmath>

using namespace std;

class student_records
{
    private:
        double quiz1, quiz2, midterm_exam, final_exam;
        float weighted_avg;
        char final_grade;

    public:
        void setquiz1 (double q1)
        {
            quiz1 = q1;
        }
        void setquiz2 (double q2)
        {
            quiz2 = q2;
        }
        void setmidterm_exam (double mid)
        {
            midterm_exam = mid;
        }
        void setfinal_exam (double finale)
        {
            final_exam = finale;
        }

        void input()
        {
            cout << "Welcome to the Grading Program! Please enter the following information\n";

            cout << "Enter Quiz 1 and 2 results out of 10 points: ";
            cin >> quiz1 >> quiz2;

            cout << "Enter Mid-term result out of 100 points: ";
            cin >> midterm_exam;

            cout << "Enter Final exam result out of 100 points: ";
            cin >> final_exam;
        }

        void weightavg ()
        {
            weighted_avg = ((quiz1 + quiz2)/20 * 0.25 + midterm_exam / 100 * 0.25 + final_exam / 100 * 0.5) * 100;
        }

        void finalg ()
        {
            if (weighted_avg >= 90)
    {
        final_grade = 'A';
    }
    else if (weighted_avg >= 80)
    {
        final_grade = 'B';
    }
    else if (weighted_avg >= 70)
    {
        final_grade = 'C';
    }
    else if (weighted_avg >= 60)
    {
        final_grade = 'D';
    }
    else
    {
        final_grade = 'F';
    }
        }

        double getquiz1 ()
        {
            return (quiz1);
        }
        double getquiz2 ()
        {
            return (quiz2);
        }
        double getmidterm_exam ()
        {
            return (midterm_exam);
        }
        double getfinal_exam ()
        {
            return (final_exam);
        }
        double getweighted_avg ()
        {
            return (weighted_avg);
        }
        double getfinalg ()
        {
            return (final_grade);
        }

};

int main()
{
    student_records values, final_avg, grade, s;

    values.input();
    final_avg.weightavg();
    grade.finalg();

    cout << "The average is " << s.getweighted_avg() << " and your final grade is " << s.getfinalg();
    return 0;
}

Output is:

Welcome to the Grading Program! Please enter the following information
Enter Quiz 1 and 2 results out of 10 points: 10
10
Enter Mid-term result out of 100 points: 100
Enter Final exam result out of 100 points: 100
The average is 1.46101e-38 and your final grade is 0

student_records::input() is assigning the inputted values to local variables, and not to the class member variables. So these class member variables remain uninitialized by the time you come to wanting to use them.

Then, in main() you use too many instances of student_records . You only need one!

student_records s;
s.input();
s.weightavg();
s.finalg();

So I see you are using Getters and Setters. That is a really good practice. And to answer your question on using member functions, you have used them correctly.

You can also define the member functions outside the class.

Coming to your main question, in your input() function you have not called the Setter functions to set the data members in your class hence they do not hold any value.

You can call the setters after getting the local variables from stdin.

And it also seems like your local variable info is being unused, make sure to comment that if not in use.

There are 2 problems:

  • In main(), you create 4 instances of student_record, but you need only one of them (s, let´s say). Remove the others and replace “values.input()” with “s.input()” etc.
  • In input(), you assing values not to the member variables of the object, but to the local variables that are forgotten when the function ends

Let's look at what you are doing removing student_records info; from void input(); , and you have a choice depending on how you want to do it. As mentioned in the comments, when you declare student_records info; inside void input() , the instance info will go out of scope and be deconstructed after input() returns. (good thing it is unused)

With classes, member functions and friend functions have access to the class private: variables. If you choose to take input in input() , you can operated directly on the private: variables quiz1, quiz2, midterm_exam, final_exam; without needing any local variabled. However, you can also choose to read into local variables and then call your setter functions, eg void setquiz1 (double q1) passing the local variable for quiz 1 as a parameter (this just adds negligible bit of overhead).

Now let's look at how you try and use the class instance s in main() . You want to output results with:

    std::cout << "The average is " << s.getweighted_avg() << 
                " and your final grade is " << s.getfinalg() << '\n';

Which is 100% doable with tiny tweaks to your existing class. If you choose to do it that way, you are not using your getters and setters, but rather you are doing the following:

#include <iostream>

class student_records
{
    private:
        double quiz1, quiz2, midterm_exam, final_exam;
        float weighted_avg;
        char final_grade;

    public:
        void input()
        {
            std::cout << "Welcome to the Grading Program! "
                         "Please enter the following information\n";

            std::cout << "Enter Quiz 1 and 2 results out of 10 points: ";
            if (!(std::cin >> quiz1 >> quiz2)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            
            std::cout << "Enter Mid-term result out of 100 points: ";
            if (!(std::cin >> midterm_exam)) {
                std::cerr << "error: numeric input.\n";
                return;
            }

            std::cout << "Enter Final exam result out of 100 points: ";
            if (!(std::cin >> final_exam)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
        }

        void weightavg ()
        {
            weighted_avg = ((quiz1 + quiz2)/20 * 0.25 + midterm_exam / 100 * 0.25 +
                            final_exam / 100 * 0.5) * 100;
        }

        void finalg ()
        {
            if (weighted_avg >= 90)
            {
                final_grade = 'A';
            }
            else if (weighted_avg >= 80)
            {
                final_grade = 'B';
            }
            else if (weighted_avg >= 70)
            {
                final_grade = 'C';
            }
            else if (weighted_avg >= 60)
            {
                final_grade = 'D';
            }
            else
            {
                final_grade = 'F';
            }
        }

        double getweighted_avg ()
        {
            weightavg();
            return (weighted_avg);
        }
        char getfinalg ()
        {
            finalg();
            return (final_grade);
        }

};

int main ()
{
    student_records s{};
    
    s.input();
    
    std::cout << "The average is " << s.getweighted_avg() << 
                " and your final grade is " << s.getfinalg() << '\n';
    return 0;
}

( note: the addition to double getweighted_avg () and char getfinalg () to ensure weighted_avg is calculated and the return type for getfinalg() has been changed to char .)

( also note: the validation of EVERY input)

Example Use/Output

With those changes, you would get:

$ ./bin/student_weighted_avg
Welcome to the Grading Program! Please enter the following information
Enter Quiz 1 and 2 results out of 10 points: 10 10
Enter Mid-term result out of 100 points: 100
Enter Final exam result out of 100 points: 100
The average is 100 and your final grade is A

Now after your explanation, I suspect you are supposed to do is decouple your interface (how you talk to the user and get input) from your implementation (your class and your calculations). That is one of the primary goals in object oriented programming. Don't mix your interface and implementation (it's not a peanut butter cup)

From that standpoint, you can choose whether to make input() a member function, or make it wholly separate and pass a reference to a class instance as a parameter. Leaving it as a member function, you would then do:

        void input()
        {
            double q1, q2, mt, fe;
            
            std::cout << "Welcome to the Grading Program! "
                            "Please enter the following information\n";
        
            std::cout << "Enter Quiz 1 and 2 results out of 10 points: ";
            if (!(std::cin >> q1 >> q2)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setquiz1 (q1);
            setquiz2 (q2);
            
            std::cout << "Enter Mid-term result out of 100 points: ";
            if (!(std::cin >> mt)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setmidterm_exam(mt);
        
            std::cout << "Enter Final exam result out of 100 points: ";
            if (!(std::cin >> fe)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setfinal_exam(fe);
            
            weightavg();
            finalg();
        }

You would remove the additions to getweighted_avg() and getfinalg() , so your entire code would work as:

#include <iostream>

class student_records
{
    private:
        double quiz1, quiz2, midterm_exam, final_exam;
        float weighted_avg;
        char final_grade;

    public:
        void setquiz1 (double q1)
        {
            quiz1 = q1;
        }
        void setquiz2 (double q2)
        {
            quiz2 = q2;
        }
        void setmidterm_exam (double mid)
        {
            midterm_exam = mid;
        }
        void setfinal_exam (double finale)
        {
            final_exam = finale;
        }

        void input()
        {
            double q1, q2, mt, fe;
            
            std::cout << "Welcome to the Grading Program! "
                            "Please enter the following information\n";
        
            std::cout << "Enter Quiz 1 and 2 results out of 10 points: ";
            if (!(std::cin >> q1 >> q2)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setquiz1 (q1);
            setquiz2 (q2);
            
            std::cout << "Enter Mid-term result out of 100 points: ";
            if (!(std::cin >> mt)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setmidterm_exam(mt);
        
            std::cout << "Enter Final exam result out of 100 points: ";
            if (!(std::cin >> fe)) {
                std::cerr << "error: numeric input.\n";
                return;
            }
            setfinal_exam(fe);
            
            weightavg();
            finalg();
        }
        
        void weightavg ()
        {
            weighted_avg = ((quiz1 + quiz2)/20 * 0.25 + midterm_exam / 100 * 0.25 +
                            final_exam / 100 * 0.5) * 100;
        }

        void finalg ()
        {
            if (weighted_avg >= 90)
            {
                final_grade = 'A';
            }
            else if (weighted_avg >= 80)
            {
                final_grade = 'B';
            }
            else if (weighted_avg >= 70)
            {
                final_grade = 'C';
            }
            else if (weighted_avg >= 60)
            {
                final_grade = 'D';
            }
            else
            {
                final_grade = 'F';
            }
        }

        double getquiz1 ()
        {
            return (quiz1);
        }
        double getquiz2 ()
        {
            return (quiz2);
        }
        double getmidterm_exam ()
        {
            return (midterm_exam);
        }
        double getfinal_exam ()
        {
            return (final_exam);
        }
        double getweighted_avg ()
        {
            return (weighted_avg);
        }
        char getfinalg ()
        {
            return (final_grade);
        }

};

int main ()
{
    student_records s{};
    
    s.input();
    
    std::cout << "The average is " << s.getweighted_avg() << 
                " and your final grade is " << s.getfinalg() << '\n';
    return 0;
}

(result is the same)

So either way is fine, I suspect this last way is closer to what you are asked to do. Consider also simply removing input() as a member function and passing a reference. That would completely separate interface and implementation. Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM