Home > Enterprise >  Avg of objects c
Avg of objects c

Time:04-13

I am trying to solve how to get the average of 2-4 objects ideally with the method beeing inside my class.

class Student {

public:
    string name;
    int grades;

public:
    void val(string name, int grades) 
    {
        this->name = name;
        this->grades = grades;
    }
};

int main() {
    Student p1,p2,p3,p4;
    p1.val("john", 10);
    p2.val("dean", 5);
    p3.val("george", 11);
    p4.val("fred", 19);
    cout << p1.name << " " << p1.grades << endl;
    cout << p2.name << " " << p2.grades << endl;
    cout << p3.name << " " << p3.grades << endl;
    cout << p4.name << " " << p4.grades << endl;
    return 0;
}

i just cant figure out a way to get for example the average of p1.grades/p2.grades/p3.grades/p4.grades ideally i want the method in the class and if possible the answer as simple as possible (nothing too advanced to understand).

CodePudding user response:

You can use just a for loop as for example

int sum = 0;
for ( const Student *student : { &p1, &p2, &p3, &p4 } )
{
    sum  = student->grades;
}

int average = sum / 4;

CodePudding user response:

There are many "clever" ways you could express this in C , but there are come fundamentals of programming in general and OOP specifically that you should incorporate into this exercise before getting in to more advanced C .

First of all, if you have more than one of an object to be processed together as a collection then you should use a container or array that may be iterated. The simplest container in C is an array - they are built-in to the language rather than part of the library. There are all sorts of reasons why in practice you might not use an array, but for this exercise perhaps the simplicity makes it appropriate - one thing at a time.

So instead of four discrete objects p1, p2 etc. you might have Student p[4] ;.

Your class design could be improved. For example in OOP, it is generally bad form to expose data members as public. Hiding the data and controlling access via member functions is preferred. Moreover since your class has no constructor, it is possible to instantiate an "empty" Student with no name or grade. That might be useful, but you should at least have an initialiser constructor so that the objects can be instantiated and initialised in the same expression. That would for example allow your student array to be instantiated and initialised thus:

   // An initialised array of students
   Student students[] = { Student("john", 10),
                          Student("dean", 5),
                          Student("george", 11),
                          Student("fred", 19) } ;

The number of elements in students in this case is fixed and determined by the number of initialisers and has value sizeof(students) / sizeof(*students). This is one reason you might in practice prefer a more flexible container such as a std::vector, but that is perhaps another question.

So the Student class might then look like:

class Student 
{
    public:
        // Constructor with initialiser list
        Student(std::string name, int grades) : m_name(name),
                                                m_grades(grades)
        {}

        // Read-only member accessors
        std::string name(){ return m_name ; }
        int grades(){ return m_grades ; }

    private :
        std::string m_name;
        int m_grades;

};

Now given that the array can be iterated by indexing zero to sizeof(students) / sizeof(*students) - 1, you can output the data and accumulate the grade sum as follows:

int student_count = sizeof(students) / sizeof(*students) ;
double grade_sum = 0 ;

for( size_t i = 0; i < student_count; i   )
{
    int grade = students[i].grades() ;
    std::cout << students[i].name() << " " << students[i].grades() << std::endl ;
    grade_sum  = grade ;
    
}

And then report the grade average thus:

std::cout << "Grade avg. = " << grade_sum / student_count << std::endl ;

Pulling all that together:

#include <string>
#include <iostream>

class Student 
{
    public:
        Student(std::string name, int grades) : m_name(name),
                                                m_grades(grades)
        {}

        std::string name(){ return m_name ; }
        int grades(){ return m_grades ; }

    private :
        std::string m_name;
        int m_grades;

};

int main() 
{
    Student students[] = { Student("john", 10),
                           Student("dean", 5),
                           Student("george", 11),
                           Student("fred", 19) } ;

    int student_count = sizeof(students) / sizeof(*students) ;
    double grade_sum = 0 ;
    
    for( size_t i = 0; i < student_count; i   )
    {
        int grade = students[i].grades() ;
        std::cout << students[i].name() << " " << students[i].grades() << std::endl ;
        grade_sum  = grade ;
        
    }
    
    std::cout << "Grade avg. = " << grade_sum / student_count << std::endl ;

    return 0;
}

With respect to:

"ideally i want the method in the class"

That does not really make much sense. The class represents a single student, whilst the average pertains to the collection of Student objects. However - if you really must then, you could make the grade sum and student count static members and accumulate the count and sum as students are instantited via the constructor thus:

class Student 
{
    public:
        Student(std::string name, int grades) : m_name(name),
                                                m_grades(grades)
        {
            m_grade_sum  = grades ;
            m_student_count   ;
        }

        std::string name(){ return m_name ; }
        int grades(){ return m_grades ; }
        
        static double averageGrade() 
        { 
            return static_cast<double>(m_grade_sum) / m_student_count ;
        }
        
        static int Count(){ return m_student_count; }

    private :
        std::string m_name;
        int m_grades;
        static int m_grade_sum ;
        static int m_student_count ;

};

int Student::m_grade_sum = 0 ;
int Student::m_student_count = 0 ;

Then the main() becomes:

int main() 
{
    Student students[] = { Student("john", 10),
                           Student("dean", 5),
                           Student("george", 11),
                           Student("fred", 19) } ;

    for( size_t i = 0; i < Student::Count(); i   )
    {
        int grade = students[i].grades() ;
        std::cout << students[i].name() << " " << students[i].grades() << std::endl ;
    }
    
    std::cout << "Grade avg. = " << Student::averageGrade() << std::endl ;

    return 0;
}

It gets complicated and error prone perhaps when you might need to remove and/or amend Students after instantiation.

  • Related