CS 1440 Lab 7

Pre-Lab

### Background

In Chapter 2, you learned that variables are names of memory locations.  You also have been told that you should use meaningful variable names.  So, if you are required to write a grading program that asks for test grades and computes the average of the grades, you may use variables like the ones named below:

int  count;
double  test, total, average;

Now, suppose that in addition to the average, your program must preserve the values of each test grade.  Then you can’t “reuse” the test variable each time.  You may then have a group of test variables; maybe named something like: test1, test2, test3 etc.

Now suppose that you need to do this for 10 students where each student has 3 test grades.  You need to preserve the test grades, average them together, preserve the students names, and their final letter grades.  You might end up with a bunch of variables (6 per student) like these:

string name_1, grade_1;      /** student 1 **/
double test_1_1, test_1_2, test_1_3, average_1;

string name_2, grade_2;           /** student 2 **/
double test_2_1, test_2_2, test_2_3, average_2;
.  .  .
.  .  .
string name_10, grade_10;         /** student 10 **/
double test_10_1, test_10_2, test_10_3, average_10;

What is really going on here?  What you have is a bunch of variables to maintain information about a student: name, grade, tests, average.  With some clever variable naming you can keep track for many students.  But C++ gives us more powerful ways to combine together memory locations than just a clever naming scheme.

Just as C++ lets us define our own functions, C++ also lets us define our own data types.  For the above example, we need a type that combines together information about a student.  C++ lets us define either a struct or a class to do this.  We’ll briefly cover structs then spend most of our time on classes.

STRUCTS

To “group” the student information together into a new struct data type, we say in C++:

struct  Student
{
double  test1, test2, test3;
double  average;
};

This does not create a variable, it just defines a data type.  We use this new data type in a variable declaration just like you’ve been doing with the base C++ types (like int or double).  So I can have 10 student variables by declaring:

Student  student1, student2, . . . , student10;

So, now your program really only has 10 variables (compared with 60 above), but each of these variables is a collection of memory locations as defined by the Student struct data type.  Each variable of this data type collects 6 named memory locations: name, grade, test1, test2, test3, and average.  So how do you print out student3’s name?  By using a member selector statement to select the name member of student3:

cout  <<  student3.name  <<  endl;

The dot is the member selection operator and can be used to access the data members for input, output, and other expressions you are familiar using.  It usually does not make sense to use the entire collection in an expression.  See how the following don’t make sense:

student1 = "Jane";  // student1’s name?
student1 = 100;     // student1’s test1 grade?

However, it does make sense to refer to the entire struct when you want to pass the entire collection to a function, as in:

print_information(student1);  /* prints name, average,

You can “hierarchically” arrange structs too!  This just means that one of your structs can contain a data member that is a different struct!  As an example, maybe I have a struct like below for courses (that contain students):

struct  Course
{
string  name;
int  section;
Student  student1, student2, . . ., student10;
};

Course  cs1440, cs3460, cs4667;

Notice that  cs1440.name  and  cs1440.student1.name  are different data members (memory locations) even though the “last” member names are the same.  Also notice how you select “nested” data members using multiple dots.

CLASSES

Classes are another way C++ lets us combine together distinct but related memory locations.  Classes are more powerful and versatile than structs which is why we will focus on them rather than structs.  Classes are more powerful because in addition to combining related data together we also get to define the functions that are appropriate for that kind of data.  Remember when you used file streams a few weeks ago?  You declared a stream variable, then “opened” the Unix file you wanted to associate with that variable.

ifstream  fin;
fin.open("myfile.txt");

Well, ifstream is a defines a “class” data type.  In addition to some data members (like we saw with structs earlier) this class defines some function members like open, close, fail, eof, and others too!