Hey there, I'm having trouble getting my program to display the students and class summary using classes. What I'm unsure of is where the problem lies, whether it is a displacement of set/get functions or the content in my StoreStudent function is incorrect, or perhaps something else I might have missed. Anyways, any help, guidance, or helpful sites maybe, would be extremely helpful. This is my code so far:

# include <iostream>
# include <iomanip>
# include <string>
# include <fstream>
using namespace std;

#ifndef STUDENT_H
#define STUDENT_H

// Class

class Student{
      private:
         string name,
                last;
         int age;
         char gender;
         int size;
         int *gptr;
      public:
         Student();
         Student(int, int);
         ~Student();
         
         int CreateStudent();
         void StoreStudent(string, string, string, int, char, int[], int);
         void DisplayStudent();
         char StudentGrade(int);
         int StudentAvg(int []);

		 void setName(string);
		 string getName();
		 void setLast(string);
		 string getLast();
		 void setAge(int);
		 int getAge();
		 void setGender(char);
		 char getGender();
};
#endif
// This programa creates a miniregister that allows the user
// to create classes, insert students into those classes,
// display the students records of the classes, as well as
// show the class summary.

#include "Student.h"
# include <iostream>
# include <iomanip>
# include <string>
# include <fstream>
using namespace std;

//Prototypes

bool CheckClass(string ClassName);
int CreateClass();
void DisplayClass();
void Instructions(void);
int Menu(void);

Student::Student(){                                                        
     gptr = new int[3];
	 size = 0;
}

Student::Student(int n, int m_size){
     gptr = new int[n];
	 size = m_size;
}

Student::~Student(){
	delete[] gptr;
}

void Student::setName(string N){
	name = N;
}

string Student::getName(){
	return name;
}

void Student::setLast(string l){
	last = l;
}

string Student::getLast(){
	return last;
}

void Student::setAge(int a){
	age = a;
}

int Student::getAge(){
	return age;
}

void Student::setGender(char g){
	gender = g;
}

char Student::getGender(){
	return gender;
}


int main()
{
  // Declaring variables
  int option = 0;
  Student person;

// Este while es para que el programa siga corriendo mientras que sea escogido uno de los 5 optiones.
  while (option >= 1 || option <= 5){
        // Display instructions
        Instructions();
  
        // Display menu
        option = Menu();

        // Desplega la option escogida por el usuario
        cout << "You've chosen option: " << option << endl << endl;

        if (option == 1){ // Creates a class if it does not exist  
           CreateClass();
           }
        else if(option == 2){ // Adds a student record to a class (if it exists)
           person.CreateStudent();
           }
        else if(option == 3){ //
           person.DisplayStudent();
           }
        else if(option == 4){
           DisplayClass();  
           }
        else if(option == 5){     
           return 0;
           }

  }
} // End main

//Functions

void Instructions(){
cout << "This program allows the user to create a class and input student records. \n" << endl;
}

int Menu(){

  int option;

  cout << "Menu:" << endl;
 
cout << "\t1) Create Class" << endl;
cout << "\t2) Insert Student Record" << endl;
cout << "\t3) Display Class Students" << endl;
cout << "\t4) Display Class Summary" << endl;
cout << "\t5) Exit Program \n" << endl;
   
     cout << "Choose an option from the Menu: " << endl;
     cin >> option;
     while ((option < 1) || (option > 5)){
                 cout << "Error: Choose between the options 1-5: " << endl;
                 cin >> option;
                 }
     
     return option;
}

bool CheckClass(string ClassName){
// This function verifies to see whether the class exists or not

    fstream Class;
    ClassName.append(".dat");
     
    Class.open(ClassName.c_str(),fstream::in);
    if (Class.good()){
        Class.close();
        return true ;
    }
    return false;
}    

int CreateClass (){
    // This function creates a file for the class entered
    
     fstream Class;
     string ClassName;
  
     cout << "Enter a class: " << endl;
     cin >> ClassName;
     
     if (CheckClass(ClassName)==false)
     {
        ClassName.append(".dat"); // Adds ".dat" to the file
    
        Class.open(ClassName.c_str(),fstream::out);
    
        cout << "The class " << ClassName << " was created" << endl;
    
         Class.close();    
         return 0;
    }
    else
    {
         cout << "The class already exists." << endl;
         return 1;
    }
}



void DisplayClass (){
    //This function displays the summary of the class
     
     string name;  // Variable of the first name
     string last; // Variable that contains the last name
     int age; // Variable of the age
     char gender;  // Variable of the gender
     int size; 
     int *grade;
     int i = 0, k;
     
     int *gradetotal; //={0,0,0,0,0};
     int AgeTotal = 0;    
          
     int *gradeavg; // Variable used to store the average of each grade
     int AgeAvg = 0;   // Variable used to store the average age
     int male = 0;  
     int female = 0; 
    
     ifstream Class;
     string ClassName;
    
     cout << "Enter a class: " << endl;
     cin >> ClassName;
    
     ClassName.append(".dat");
     Class.open(ClassName.c_str(),fstream::in);
    
    if(!Class){
         cout << "Opening file " << ClassName << " for reading \n\n";
         cout << "The file could not be opened! " << endl;
         cout << "Possible errors: " << endl;
         cout << "The class does not exist. " << endl;
         exit(1);   // Exits program.
     }
     
         Class >> name >> last >> age >> gender >> size; //>> grade[0] >> grade[1] >> grade[2] >> grade[3] >> grade[4];  
		 grade = new int[size];
         for (k = 0; k < size; k++){
			 Class >> grade[k];
		 }

		 while(!Class.eof()){
            
            gradetotal = new int[size];
            /*gradetotal[0] += grade[0];
            gradetotal[1] += grade[1];
            gradetotal[2] += grade[2];
            gradetotal[3] += grade[3];
            gradetotal[4] += grade[4];*/ 
                        
			for (int m = 0; m < size; m++){
				gradetotal[m] += grade[m];
			}

            AgeTotal += age;
            
            if (gender == 'M' || gender == 'm'){
               male++;
            }
            else if (gender == 'F' || gender == 'f'){
               female++;
            }
            i++; 
            
            Class >> name >> last >> age >> gender >> grade[0] >> grade[1] 
            >> grade[2] >> grade[3] >> grade[4];                  
            }
			
			gradeavg = new int[size];

            /*gradeavg[0] = gradetotal[0]/i;
            gradeavg[1] = gradetotal[1]/i;
            gradeavg[2] = gradetotal[2]/i;
            gradeavg[3] = gradetotal[3]/i;
            gradeavg[4] = gradetotal[4]/i;*/

			for (int n = 0; n < size; n++){
				gradeavg[n] = gradetotal[n]/i;
			}
                        
            AgeAvg = AgeTotal/i;
         
         // Displays the actual class summary
         cout << "\n";
         cout << "Exams Summary " << endl; 
         
         for(int j = 0; j < size; j++){                 
                 cout << "Exam " << j << "Average:" << setprecision(2) 
                 << gradeavg[j] << endl;
         }
         
         
         cout << "Gender Summary " << endl;
         cout << "Females:" << female << endl;
         cout << "Males:" << male << endl << endl;
         
         cout << "Age Average:" << AgeAvg << "\n" << endl;
}
      
int Student::CreateStudent (){
    // This function allows the user to insert as many students he/she wants
    // to the class
    
  // Variables required for the function
  int w_age;
  string w_name;
  string w_last;
  char w_gender;
  int w_size;
  int *grade;
  int j, i;
  int students;
  Student person;
 
    fstream Class;
    string ClassName;
    
    cout << "Enter a class: " << endl;
    cin >> ClassName;
    
    
    if (CheckClass(ClassName)==true){              
         cout << "How many students would you like to enter: " << endl;
         cin >> students;
         
         for (i = 0; i < students; i++){
             // Asks the user how many students he/she would like to enter
             // and for each one it asks the user to enter the student record
             cout << "Enter student information: " << endl;
             cout << "Enter first name: " << endl;
             cin >> w_name;
             cout << "Enter last name: " << endl;
             cin >> w_last;
             cout << "Enter age: " << endl;
             cin >> w_age;
             cout << "Enter gender: (M or F)" << endl;
             cin >> w_gender;
             cout << "How many grades would you like to enter? " << endl;
             cin >> w_size;
             //Student Student(w_size);
             grade = new int[w_size];
             cout << "Now enter " << w_size << " grades:" << endl;
             for (j = 0; j < w_size; j++){
                 cout << "Enter grade " << j + 1 << ": " << endl;
                 cin >> grade[j];
             }

		 person.setName(w_name);
		 person.setLast(w_last);
		 person.setAge(w_age);
		 person.setGender(w_gender);
         
		 person.getName();
		 person.getLast();
		 person.getAge();
		 person.getGender();

         person.StoreStudent(ClassName, w_name, w_last, w_age, w_gender, grade, w_size); // Calls the function to store the student
         }
         return 0;
    }
    else {
         cout << "Class does not exist. " << endl;
         return 1;
     }
}     

void Student::StoreStudent(string ClassName, string name, string last, int age, char gender,int grade[], int size){
    // This function stores the student information into the file
    
    ofstream Class;
    
    ClassName.append(".dat");
    
    Class.open(ClassName.c_str(),fstream::app | fstream::out);
    
    Class << name << endl;
    Class << last << endl;
    Class << age << endl;
    Class << gender << endl;
    Class << size << endl;
    Class << grade << endl;
    for(int i = 0; i < size; i++){
            Class << grade[i] << endl;
    }
          
    Class.close(); 
    
}
     
void Student::DisplayStudent(){
    int w_age;
    string w_name;
    string w_last;
    char w_gender;
    int size;
    int *grade;
    int w_average;
    Student person;
    
    ifstream Class;
    string ClassName;
    
     cout << "Enter a class: " << endl;
    cin >> ClassName;
    
    cout << "\n";
    if (CheckClass(ClassName)==true){
         ClassName.append(".dat"); // Adds ".dat" to the file
         Class.open(ClassName.c_str(),fstream::in);
         
         //Class >> size;
         
         Class >> name >> last >> age >> gender >> size; 
         grade = new int[size];
         for (int i = 0; i < size; i++){
             Class >> grade[i];
         }
         
         while(!Class.eof()){
            w_average = person.StudentAvg(grade);
             
             cout << name << " " << last << setw(10) << age << setw(5) 
             << gender << setw(5); 
             for (int j = 0; j < size; j++){
                 cout << grade[j] << setw(5);
             }
             cout.precision(2);
             cout << w_average;
             cout << "  " << person.StudentGrade(w_average) << endl;
             
             Class >> name >> last >> age >> gender >> size;
             for (int k = 0; k < size; k++){
                 Class >> grade[k];
             }
         }
         
         cout << "\n" << endl;
         
         Class.close(); 
         //return 0;
    }
    else {
         cout << "Class does not exist. " << endl;
         //return 1;
     }
}      
      
char Student::StudentGrade(int avg)
{
// This function determines the letter grade
// of a student based on the average

     char lettergrade; // Variable used to store the corresponding letter grade
     if (avg >= 90)
	     lettergrade = 'A';
	  else if (avg >= 80)
	     lettergrade = 'B';
	  else if (avg >= 70)
	    lettergrade = 'C';
	  else if (avg >= 60)
	     lettergrade = 'D';
      else 
         lettergrade = 'F';
    
      return lettergrade;
}

int Student::StudentAvg(int grade[]){ // Still has yet to be fixed
// Function to determine the average grade of the student

      int total = 0;   //variable de conteo para el promedio
      int avg; //variable para guardar el promedio
      
      for (int i = 0; i < 5; i++)
{
           
           total += grade[i];
          
}
      
      avg = total/5;
      
      return avg;
      
}

Any help would be appreciated, thanks, and for any clarifications, just let me know.

I prefer spaghetti bolognese to spaghetti code... boy, isn't this a mess! I think you will have to start from the start again. This is object-oriented programming. So first of all, you need to decide what data and functionality go together. In this case, it's not a very tough software design problem, you obviously have two classes to make: Class and Student. So lets examine each of them:

Class:
Data:
- should store the list of students in the class, i.e. std::vector<Student>
- should store the name of the Class, i.e. std::string (for "first grade" or else)
- should store the number of grades in the Class, since all students have equal number of grades.
Functionality (Methods):
- should be able to prompt the user for the name of the Class, the number of grades, the number students, and the students themselves.
- should be able to save all its data to a file.
- should be able to load all its data from a file.
- should be able to display the entire class on screen (std::cout).
- should be able to calculate statistics such number of girls and boys, class average for each grade, etc.

So the above is pretty much exactly how you class Class should be made. And you already have most of the code to do this, but you need to structure it properly because now all you have is spaghetti. For the student class, you already have a good start.

Student:
Data:
- should store a name and a last_name
- should age and gender
- should store the list of grades, i.e. std::vector<int>
Functionality:
- should be able to prompt the user for all the above data.. this would be called by the prompt function in Class, for each new student.
- should be able to save all its data to a file.. this would be called by the save function in Class, for each student.
- should be able to load all its data from a file.. this would be called by the load function in Class, for each new student.
- should be able to display the student information on screen (std::cout).. again used by Class::display.
- should be able to calculate average grade.. this would be called by Student::display.


With the above, you should be able to consolidate your code in more structured fashion. The central idea here is encapsulation, this means each class in the program holds the data and functionality that is relevant to that class only, hides it from the world, and leaves the rest to other classes. Remember, the save and load functions deal with the file IO, no other functions should save and load to file (in your code now, you have WAY too much reading and writing to file for every purpose... use the RAM more than the hard-drive, it's much safer, less error-prone!).

At the end, you should be able to have a main function that looks like this:

int main()
{
  int option = 0;
  Class current_class; //only need one instance of Class, or more (vector<Class> if you want to have the user define several classes.

  while (option >= 1 || option <= 5){
    // Display instructions and get Menu
    Instructions();
    option = Menu();
    cout << "You've chosen option: " << option << endl << endl;

    if (option == 1){ // Creates a class if it does not exist  
      current_class.promptUser();
      current_class.save();
    } else if(option == 2){ // Adds a student record to a class (if it exists)
      current_class.addStudent();
      current_class.save();
    } else if(option == 3){ //
      current_class.displayStudentsOnly();
    } else if(option == 4){
      current_class.display();
    } else if(option == 5){     
      return 0;
    }
  }
} // End main

Final thought, indenting your code correctly will help you, me, and the whole world be able to read your code better and find mistakes faster.

But what of constructors and get/set? Also, what of the function addStudent? Is that supposed to work somewhat like a resize function for students and if not, why would it be located in the class Class? Btw thanks, and I'll make sure I properly indent my program so it looks better, from now on.

Edited 6 Years Ago by crodriguez08: n/a

>>But what of constructors and get/set?
Well of course, constructors/destructors too, I didn't mention them because they are implied and I generally don't include them under "functionality" per se, they are more a part of "data" because they generally just initialize and clean up the data. As for get/set functionalities, well sure you can put them, but ask yourself, do you really need them? Often, as in your case, the data members can just be made public because they can be considered as part of the "interface" of the class. But either way you like is fine, public data members, or private data with get/set methods, or just private data with no get/set, doesn't make much of a difference in this case, IMO. If you ask me I use, most of the time, private/protected data with no get/set, in the spirit of the RAII idiom, i.e., Resource Allocation Is Initialization, but you don't need to worry about that at this point, do as you like.

>>Also, what of the function addStudent? Is that supposed to work somewhat like a resize function for students
YES, just like the push_back function in std::vector. Just adds a student to the list of students that belong to one Class, and probably calls the Student::promptUser() function to fill the data for the student at the same time.

>>why would it be located in the class Class?
This is called "ownership", a Student is owned by a Class, because a Class has a list of Students and a Student belongs to one and only one Class. If this last statement makes sense in the real world, it makes sense in the "virtual world" of your program too. It can only be in the class Class, because an object's method acts on the object's data members. So, does it make sense to say "I add a student to a student" or does it make more sense to say "I add a student to a class"? If the latter makes more sense, it means the function AddStudent() must be located in class Class, not in the class Student or even worse as a global function.

Hmm, I see, and is there a substitution for vectors, because my professor hasn't taught us anything about it although it seems convenient. While I'm considering the possibility of learning about vectors and using it, my other option would be dynamic arrays right? Or are vectors absolutely necessary?

Edited 6 Years Ago by crodriguez08: n/a

Sure, you can use a dynamic array. I could say you can use a linked-list too, but that may be to big a step. So, yeah, if you didn't get to std::vector in your class, then I guess you should use a dynamic array, but it will be a bit more work for allocating and reallocating new memory for each add student. But if he didn't forbid you to use vectors, then maybe it's worth a look.

Would int size have to go in the class Student, because if so, I'd have to make a set/get function for that as well, but I'm unsure

I think the size (as in gradeCount, which is a more obvious name of the variable btw) NEEDS to be in the Student class because the Student holds the list of grades, so it has to know how many there are. Additionally, gradeCount SHALL be in the class Class also because all students in the Class have the same number of grades.

As for get/set methods, it's not a great idea. The gradeCount is attached to the size of this "grade" array, so changing it means changing the amount of grades too (size of the grade array). So get() is fine, but a simple set() would be wrong. If you want to change the number of grades, which I don't think you need to do, then you should have a more obvious special function like a resize() or something.

I suggest strongly, that you hold the gradeCount in the class Class and pass it to the constructor of every new student (like you have done already), to initialize the grade array to its required size and then provide no means of changing the number of grades for a student by NOT providing a setGradeCount() or resizeGrades() or any similar method in Student.

..unless your prof requires it, of course, in that case, I can't do anything about your prof's poor judgment, and you will have to implement a resize method, probably with a re-prompt for the user to enter the new grade list again.

This article has been dead for over six months. Start a new discussion instead.