25.5 Putting It All Together

I l @ ve RuBoard

Now let's use our knowledge of the STL to create a class to handle a simple class roster and waiting list. The class class_stuff will contain member functions to perform the following tasks :

  • Add a student to a class. If the class is full, the student will be added to the waiting list.

  • Remove a student from a class. If the waiting list has a student in it, the first student on the waiting list gets put in the class.

  • Record a grade for each assignment.

  • Print a class roster including grades.

Let's start by defining the class. We'll record information about students in the class in a map . The key is the student's name , and the value is a vector containing the grades.

A vector is very similar to a list . However, it allows indexed access to its elements much the same way an array does. We will use the function size to determine the number of elements in the vector and resize to increase the size if needed.

The start of our class_stuff definition looks like this:

 class class_stuff {     public:              typedef std::vector<int> grades;        // A set of grades         std::map<std::string, grades> roster;  // Roster of current class         std::list<std::string> waiting_list;   // People waiting on the list 

Now we need to define the member functions. The first one adds a student to a class:

 void class_stuff::add_student(     const string& name  // Name of the student to add ) { 

We first check to see if the student is already in the class; if she is, we don't add her again:

 if (roster.find(name) != roster.end(  ))         return; // Already in the class, don't reuse 

Next we check to see if the number of students currently in the class has reached the limit. If there is room, we add the student to the class using the new_student function described below. If there is not room in the class, the student goes on the end of the waiting list:

 if (roster.size(  ) < MAX_STUDENTS) {         // Class has room, add to class         new_student(name);     } else {         // No room, put on waiting list         waiting_list.push_back(name);     } } 

The new_student function is responsible for adding a student to the roster. It creates an empty set of grades, then inserts the student into the class:

 // Insert a student into the class         void class_stuff::new_student(             const string& name  // Student to add to the class         )         {             grades no_grades;   // Empty grade vector             roster.insert(pair<string, grades>(name, no_grades));         } }; 

The code to drop a student first checks to see if the student is actually in the class; he can't be dropped if he's not enrolled:

 void class_stuff::drop_student(     const string& name  // Name of the student to drop ) {     // The student we are probably going to drop     map<string, grades>::iterator the_student =         roster.find(name);     if (the_student == roster.end(  ))         return; // Student is not in the class 

Next we remove the student from the class. The erase member function eliminates an element from the map:

 roster.erase(name); 

Finally we check the waiting list and add one student from it if there's someone available:

 // Add a person from the waiting_list if      // there's anyone waiting     if (waiting_list.size(  ) > 0) {         string wait_name = waiting_list.front(  );         waiting_list.pop_front(  );         new_student(wait_name);     } } 

To record a grade, we first find the student's record:

 void class_stuff::record_grade(     const string& name,         // Name of the student     const int grade,            // Grade of this assignment                                 // Assignment number     const unsigned int assignment_number ) {     map<string, grades>::iterator the_student =         roster.find(name);     if (the_student == roster.end(  ))     {         std::cerr << "ERROR: No such student " << name << '\n';         return;     } 

Then we adjust the size of the grade vector so that it has enough entries to contain the assignment:

 // Resize the grade list if there's not enough room     if (the_student->second.size(  ) <= assignment_number)         the_student->second.resize(assignment_number+1); 

Finally, we store the value of the grade:

 the_student->second[assignment_number] = grade; } 

Our last function prints the grades for all the students in a class. To do this we need a sorted list of names. We start by copying the names from the roster into a container ( storted_names ) that can be sorted:

 void class_stuff::print_grades(  ) {     std::vector<std::string> sorted_names;        // Student names sorted     // The student we are inserting into the storted_names list     map<string, grades>::iterator cur_student;     for (cur_student = roster.begin(  );          cur_student != roster.end(  );          ++cur_student)     {         sorted_names.push_back(cur_student->first);     } 

The std:: sort function is one of the algorithms supplied by the STL. You give it a range of items to sort and it sorts them. In this case, we want to sort the entire std::vector from beginning to end:

 sort(sorted_names.begin(  ), sorted_names.end(  )); 

Now it's simply a matter of stepping through the sorted name list and printing the data. About the only new thing in this section of code is the use of [] to access elements of the roster . Remember that roster is a mapping of key to value. One way to find out the value associated with a particular key is to use the [] as follows :

   value   =   a_map   [   key   ]; 

The rest of the code for printing the grades is pretty straightforward:

 // The current student to print     std::vector<std::string>::const_iterator cur_print;     for (cur_print = sorted_names.begin(  );          cur_print != sorted_names.end(  );          ++cur_print)     {         std::cout << *cur_print << '\t';         // The grade we are printing now         grades::const_iterator cur_grade;         for (cur_grade = roster[*cur_print].begin(  );              cur_grade != roster[*cur_print].end(  );              ++cur_grade)         {             std::cout << *cur_grade << ' ';         }         std::cout << '\n';     } } 

Example 25-1 shows the full code for our class_stuff object, as well as some test code.

Example 25-1. class/class.cpp
 /********************************************************  * class_stuff -- A simple class to handle students     *  * and grades.                                          *  ********************************************************/ #include <iostream> #include <string> #include <vector> #include <map> #include <list> #include <algorithm> const unsigned int MAX_STUDENTS = 5;    // Max number of students per class // Set low for testing class class_stuff {     public:              typedef std::vector<int> grades;// A set of grades         std::map<std::string, grades> roster;   // Roster of current class         std::list<std::string> waiting_list;    // People waiting on the list     public:         // Constructor defaults         // Destructor defaults         // Copy constructor defaults         // Assignment operator     public:         void add_student(const std::string& name);         void drop_student(const std::string& name);         void record_grade(const std::string& name,                  const int grade,                 const unsigned int assignment_number         );         void print_grades(  );     private:         // Insert a student into the class         void new_student(             const std::string& name     // Student to add to the class         )         {             grades no_grades;   // Empty grade vector             roster.insert(                 std::pair<std::string, grades>(name, no_grades));         } }; /********************************************************  * class_stuff::add_student -- Add a student to a class *  *      If the class if full, add him to the waiting    *  *      list.                                           *  *********************************************************/ void class_stuff::add_student(     const std::string& name     // Name of the student to add ) {     if (roster.find(name) != roster.end(  ))         return; // Already in the class, don't reuse     if (roster.size(  ) < MAX_STUDENTS) {         // Class has room, add to class         new_student(name);     } else {         // No room, put on waiting list         waiting_list.push_back(name);     } } /********************************************************  * class_stuff::drop_student -- Remove student from     *  * a class.  If there's a waiting list his place is     *  * filled by the first student on the list.             *  ********************************************************/ void class_stuff::drop_student(     const std::string& name     // Name of the student to drop ) {     // The student we are probably going to drop     std::map<std::string, grades>::iterator the_student =         roster.find(name);     if (the_student == roster.end(  ))         return; // Student is not in the class     roster.erase(name);     // Add a person from the waiting_list if      // there's anyone waiting     if (waiting_list.size(  ) > 0) {         std::string wait_name = waiting_list.front(  );         waiting_list.pop_front(  );         new_student(wait_name);     } } /********************************************************  * class_stuff::record_grade -- Record a grade for      *  *      a student.                                      *  ********************************************************/ void class_stuff::record_grade(     const std::string& name,    // Name of the student     const int grade,            // Grade of this assignment                                 // Assignment number     const unsigned int assignment_number ) {     std::map<std::string, grades>::iterator the_student =         roster.find(name);     if (the_student == roster.end(  ))     {         std::cerr << "ERROR: No such student " << name << '\n';         return;     }     // Resize the grade list if there's not enough room     if (the_student->second.size(  ) <= assignment_number)         the_student->second.resize(assignment_number+1);     the_student->second[assignment_number] = grade; } /********************************************************  * class_stuff::print_grades -- Print the students      *  * and their grades.                                    *  ********************************************************/ void class_stuff::print_grades(  ) {     std::vector<std::string> sorted_names;      // Student names sorted     // The student we are inserting into the storted_names list     std::map<std::string, grades>::iterator cur_student;     for (cur_student = roster.begin(  );          cur_student != roster.end(  );          ++cur_student)     {         sorted_names.push_back(cur_student->first);     }     std::sort(sorted_names.begin(  ), sorted_names.end(  ));     // The current student to print     std::vector<std::string>::const_iterator cur_print;     for (cur_print = sorted_names.begin(  );          cur_print != sorted_names.end(  );          ++cur_print)     {         std::cout << *cur_print << '\t';         // The grade we are printing now         grades::const_iterator cur_grade;         for (cur_grade = roster[*cur_print].begin(  );              cur_grade != roster[*cur_print].end(  );              ++cur_grade)         {             std::cout << *cur_grade << ' ';         }         std::cout << '\n';     } } int main(  ) {     // A class for testing     class_stuff test_class;     test_class.add_student("Able, Sam");     test_class.add_student("Baker, Mary");     test_class.add_student("Johnson, Robin");     test_class.add_student("Smith, Joe");     test_class.add_student("Mouse, Micky");     test_class.add_student("Gadot, Waiting");     test_class.add_student("Congreve, William");     std::cout << "Before drop " << std::endl;     test_class.print_grades(  );     std::cout << "\n";          test_class.drop_student("Johnson, Robin");     std::cout << "After drop " << std::endl;     test_class.print_grades(  );     std::cout << "\n";     int i;     for (i = 0; i < 5; ++i)     {         test_class.record_grade("Able, Sam",      i*10+50, i);         test_class.record_grade("Baker, Mary",    i*10+50, i);         test_class.record_grade("Smith, Joe",     i*10+50, i);         test_class.record_grade("Mouse, Micky",   i*10+50, i);         test_class.record_grade("Gadot, Waiting", i*10+50, i);     }     std::cout << "Final " << std::endl;     test_class.print_grades(  );     std::cout << "\n";     return (0); } 
I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net