home *** CD-ROM | disk | FTP | other *** search
- 25-Minute Workout
- Part III Answer
- HereÆs my analysis of the problem. The two classes I chose from the description were Course and Student.
- Armed with these candidate classes, I returned to the problem description to look for verbs to be turned
- into member functions. I found the following:
- * Students enroll in courses
- * Students are graded
- * The program averages all grades in each course
- * The program returns each studentÆs grade in each course
- * The program averages each studentÆs grades from all courses in which that student is
- enrolled
- * The program calculates the average curved grade by the average grade in the class
- To enroll a student in a course and perform the necessary averages, I concluded that each Student object
- needed to know what courses it was enrolled in (like a course list) and each Course needed to know what
- students it had (like a student roll). To keep things simple, I used an array and set a maximum number of
- courses per student and a maximum number of students in each course. So that these maximums were not
- exceeded, I also needed noStudents to class Course and noCourses to Student.
- I needed also a Student::add(Course&) to add a course to the studentÆs course list and a
- Course::add(Student&) to add the student to the courseÆs student roll. These two functions handled the
- enroll verb mentioned in the preceding list.
- It wasnÆt important to me whether the application accessed these two functions through the Student class or
- the Course class; I chose Student. To keep me from forgetting and getting it wrong in use, I made
- Course::add() protected.
- The Students are graded item in the preceding list implied the need for a grade function in Student or
- Course. Is the grade a student receives in a course a property of the student or a property of the course? I
- couldnÆt find a good answer to that one, except that historically grades are kept in little books (or little
- computer databases, nowadays) associated with the course. Thus, I decided to add the member function
- Course::grade(Student&, grade). I also added member functions grade(Student&) to return a studentÆs
- grade and grade() to return the average of all students in the course, as stipulated by the requirements.
- One final member function in Course, findStudent(), is used in several member functions to find a student
- in the roll. These functions which are needed only internally should be left protected to keep the classÆs
- surface area as small as possible.
- Semester hours is obviously a property of Course, requiring a data member and a member function to set it.
- The studentÆs name is a property of Student, requiring a data member and function pair as well.
- The following is my solution to the problem along with a description of how it works. Realize that your
- solution may be different; there is no single right solution as long as youÆre trying to think like an object.
- //PROB3.CPP My solution to the Part III Workout
-
- #include <iostream.h>
- #include <string.h>
-
- const int maxStudents = 20; //max no. of students in one class
- const int maxCourses = 6; //max no. of courses student can take
-
- class Student; //Note 1
-
- class Course
- {
- friend class Student;
- public:
- Course( ) //Note 2
- {
- noStudents = 0;
- semesterHours = 3; //default is 3
- }
- ~Course( )
- {
- //nothing to do here
- }
-
- //hours - return or set the number of hours in this class
- int hours( )
- {
- return semesterHours;
- }
- int hours(int newValue)
- { //Note 3
- int oldValue = semesterHours; //itÆs customary to...
- semesterHours = newValue;
- return oldValue; //...return old value
- }
-
- //grade - return the average for the class or the grade of a
- // single student or set the grade of a single student
- float grade( ); //Note 4
- float grade(Student &s);
- void grade(Student &s, float grade);
-
- protected:
- //member functions
- //add - add a student to the roll
- int add(Student &s);
- //findStudent - find student in role
- int findStudent(Student &s);
-
- //data members
- Student *pStudents[maxStudents];
- float classGrade[maxStudents];
- int semesterHours;
- int noStudents;
- };
-
- class Student
- {
- public:
- Student( )
- {
- //just zero out everything
- noCourses = 0;
- sName[0] = æ\0Æ;
- }
- ~Student( )
- {
- //nothing to do
- }
-
- //return grade in a given course or average in all courses
- float grade(Course &c) //Note 5
- {
- return c.grade(*this);
- }
- float grade( );
-
- //return the grade compared to the class average
- float curvedGrade(Course &c);
-
- //add a student to a course
- void add(Course &c);
-
- //name - read and set name
- char *name( )
- {
- return sName;
- }
- void name(char *pName);
-
- protected:
- char sName[20];
- Course *pClasses[maxCourses];
- int noCourses;
- };
-
- //--------------Course member functions---------------------
- //grade - return the average for the class
- float Course::grade( )
- {
- //if there are no students, forget it now
- if (noStudents == 0)
- {
- return 0.0F;
- }
-
- //add æem all and return the average
- float accumGrade = 0.0F;
- for (int i = 0; i < noStudents; i++)
- {
- accumGrade += classGrade[i];
- }
- return accumGrade / noStudents;
- }
-
- //grade(Student*) - return the grade of a single student
- float Course::grade(Student &s)
- {
- //first look the student up in the student roll
- int offset = findStudent(s);
-
- //return studentÆs grade or 0 if the student wasnÆt found
- return (offset >= 0) ? classGrade[offset] : 0.0F;
- }
-
- //grade(Student, grade) - set the grade of a single student
- void Course::grade(Student &s, float grade)
- {
- int offset = findStudent(s);
- if (offset >= 0)
- {
- classGrade[offset] = grade;
- }
- }
-
- //add - add a student to the class roll; return 1 if
- // it works and a zero otherwise
- int Course::add(Student &s)
- {
- if (noStudents >= maxStudents)
- {
- cout << ôNo more room in class...maybe next semester\nö;
- return 0;
- }
- pStudents[noStudents++] = &s;
- return 1;
- }
-
- //findStudent - find a student in the look-up table;
- // return offset or -1 if canÆt find
- int Course::findStudent(Student &s)
- {
- for (int i = 0; i < noStudents; i++)
- {
- if (pStudents[i] == &s)
- {
- return i;
- }
- }
- return -1;
- }
- //--------------Student member functions-------------------
- //grade( ) - return the average grade for all courses
- float Student::grade( )
- {
- int hours;
- int noHours = 0;
- float accumGrade = 0.0F;
- for (int i = 0; i < noCourses; i++)
- {
- hours = pClasses[i]->hours( );
- accumGrade += pClasses[i]->grade(*this) * hours;
- noHours += hours;
- }
- return (noHours) ? (accumGrade / noHours): 0.0F;
- }
-
- //add - add a student to a class
- void Student::add(Course &c)
- {
- if (noCourses >= maxCourses)
- {
- cout << ôno more room in the inn\nö;
- return;
- }
- if (c.add(*this))
- {
- pClasses[noCourses++] = &c;
- }
- }
-
- //curvedGrade - return the grade curved by the average
- float Student::curvedGrade(Course &c)
- {
- //set the average to 3.0
- float g = 3.0F * grade(c) / c.grade( );
-
- //donÆt let it go over 4.0
- if (g > 4.0F)
- {
- g = 4.0F;
- }
- return g;
- }
-
- //name(char*) - store the name provided
- void Student::name(char *pName)
- {
- strncpy(sName, pName, sizeof(sName) - 1);
- sName[sizeof(sName) - 1] = æ\0Æ;
- }
-
- //--------------------test program-------------------------
- int main( )
- {
- //declare a course
- Course geo101;
-
- //give it a couple of students
- Student harry, anne;
- harry.name(ôHarryö);
- harry.add(geo101);
- anne.name(ôAnneö);
- anne.add(geo101);
-
- //grade them
- geo101.grade(harry, 3.0F);
- geo101.grade(anne, 2.5F);
-
- //now letÆs look at the averages
- cout<<ôaverage geo101 grade = ô<<geo101.grade( ) <<ô\nö;
- cout<<ôanneÆs grade = ô<<anne.grade(geo101) <<ô\nö;
- cout<<ôanneÆs curved grade = ô<<anne.curvedGrade(geo101)<<ô\nö;
-
- //letÆs look at harryÆs other course
- Course engl201;
- engl201.hours(4);
- harry.add(engl201);
- engl201.grade(harry, 2.0F);
- cout << ôharryÆs average grade = ô << harry.grade( ) << ô\nö;
-
- return 0;
- }
- In this solution, I decided that the classes Student and Course could be built dependent on each other.
- There is little chance of using class Student without Course or vice versa in some future solution. (A
- student without a course or a course without any students doesnÆt make much sense.) To be able to make
- Student a friend of Course, the class needed to be declared, hence the early declaration (Note 1).
- Starting with class Course, the constructor starts the course with an empty roll and a default of 3 semester
- hours (Note 2). The Course::hours() functions are standard. Notice, however, that when you change a data
- member value, returning the old value is an unwritten rule in C++ programming (Note 3). The
- Course::grade() members are present (Note 4), with Course::add() listed as protected, as promised.
- Continuing to class Student, you find the same types of members. One interesting point (if you will look
- out the right side of the bus, ladies and gentlemen): Student has a grade function to return an individual
- grade (Note 5). This is a duplicate of Course::grade(Student&); all it does is call that worthy function, but
- thatÆs okay. As we noted, the grade is just as much a property of the Student as it is of the Course. The
- application shouldnÆt need to worry about where the data is stored. (Also note that to call the function
- Course::grade(), the function Student::grade() makes a direct reference to this.)
- The code in the member functions is not particularly notable. The member function Course::findStudent()
- looks up a student in the roll. If it can find the student, it returns the offset. Otherwise, it returns -1. All the
- other functions include checks for a negative return from Course::findStudent().
- The main() program is childishly simple (as are most of my programs). I just declare a few courses, sign up
- a few students, grade them, and then print the individual grades, the curved grades, and the averages. The
- output from the program appears as follows:
- average geo101 grade = 2.75
- anneÆs grade = 2.5
- anneÆs curved grade = 2.727273
- harryÆs average grade = 2.428571
- Now, wasnÆt that fun?
-
-
-