Here is the account code


Reading Covered: 9,10
Reading Assigned: 11-14

Data Abstraction

We may not know what "Object Oriented" programming is, but there are certain aspects that are commonly considered Object Oriented which are very important. Data abstraction is one of them. The idea is that you often want to think of data in the world, not in terms of ints and chars, but in terms of whatever occurs most naturally for you. C++ allows you to define your own types, often called user-defined types, or data abstraction. The idea is that you define some new type (a class) and then you can declare variables of that type just like the built-in types (int, char, etc...).

Classes

So how do we write these little objects of joy? A sample class with a function that uses it is below:
#include <iostream.h>
// The declaration of our new type.
class box_car
{
public:  // Public means that anyone can access that value.
    double height, width, length; // No initialization:
    char SerialNumber[8]; // it is not allowed inside class declarations
};

double // returns the volume of the box car.
volume(box_car inBoxCar)
{
    return inBoxCar.height * inBoxCar.width * inBoxCar.length;
}

main()
{
    box_car theBoxCar;
    cout << "Input boxcar length: ";
    cin >> theBoxCar.length;
    cout << "Input boxcar height: ";
    cin >> theBoxCar.height;
    cout << "Input boxcar width: ";
    cin >> theBoxCar.width;
    cout << "Input boxcar serial number (7 chars max): ";
    cin >> theBoxCar.SerialNumber;
    cout << "The boxcar volume is: "
         << volume(theBoxCar);
}
Notice that you need to initialize all of the variables of your type, and that you use them with the period operator. Don't forget to initialize all of the data members of your class. Also the class definition does not execute any code so you can stick it in a header file so that code in other files can use your class. You can now use your class just like any other type, e.g. you can write functions that use it (like above) and you can allocate variables of it, just like any other type, either statically or dynamically. For example:
int * theBoxCar = new box_car;

Data hiding through accessor functions.

In the above function, we are always dealing with the member variables directly. This can be annoying because anyone can access them, and change them. This is because they are declared public. We can hide them by using the private keyword. But you ask, what good does a private keyword do us, if we just can't see the values then? Well, there are ways to write functions that are only good for accessing your type. They are called accessor functions, and allow you to read data from or write data into your class. (These are a type of member function. We will talk about other member functions later.) In order to write the above using data hiding, we implement it as follows:
#include <iostream.h>
#include <string.h>
// The declaration of our new type.
class box_car
{
pivate:  // Our hidden data.
    double height, width, length; // No initialization:
    char SerialNumber[8]; // it is not allowed inside class declarations
public: // The accessor functions:
// These all set values:
    void SetHeight(double newHeight); // Note that the accesors are just
    void SetWidth(double newWidth);   // regular function declarations
    void SetLength(double newLength); // inside of a class declaration.
    void SetName(char newName[]);
// This reads values:
    double  Volume();  // Now the only thing that can be read is the volume.
};

// so, now that we have all of these function declarations
// (prototypes), how do we define them?  Just like normal, except that we
// have to tell the compiler which class it is a member of, and then
// that function has local access to all of the members.

double // returns the volume of the box car.
box_car::Volume()
{
    return height * width * length;
}

void SetHeight(double newHeight)
{
    height = newHeight;
}

void SetWidth(double newWidth)
{
    width = newWidth;
}

void SetLength(double newLength)
{
    length = newLength;
}

void SetName(char newName[])
{
    strcpy(SerialNumber, newName);
}

main()
{
    box_car theBoxCar;
    double numberBuffer;
    char   stringBuffer[8];
    cout << "Input boxcar length: ";
    cin >> numberBuffer;
    theBoxCar.setLength(numberBuffer);
    cout << "Input boxcar height: ";
    cin >> numberBuffer;
    theBoxCar.setHeight(numberBuffer);
    cout << "Input boxcar width: ";
    cin >> numberBuffer;
    theBoxCar.setWidth(numberBuffer);
    cout << "Input boxcar serial number (7 chars max): ";
    cin << stringBuffer;
    theBoxCar.SetName(stringBuffer);
    cout << "The boxcar volume is: "
         << theBoxCar.Volume();
}
This lecture covers some more features of classes. Mostly we look at more uses of member functions, including constructors and destructors. We also look at more interesting uses of accessor functions.
Reading Covered: 11-14
Reading Assigned: Look through 9-14 again and make sure you understand it. Read 25-28, 30. (You'll use 25 on the homework, and we probably won't go over 26 in class. That is just for kicks. Also, If you want to know how that switch statment that I used in the code for the homework works, you can read about it in chapter 30.)

A quick reminder of classes

  • Class Definition is a description of your new type. Much like an int.
  • Class Variable is the actual instance of an object of that type. Much like any other variable, i.e. the x in int x;
  • Member Variable part of the data stored in a class. Accessable only through an instantiated class variable, by using accessor functions or the dot if it is a public variable.
  • Member Function (a.k.a. Methods) allows people to access or in some other way, use an instantialed class variable. They are declared in the class declaration and defined in the code using the :: operator.
Side note: You can define the member functions inside the class declaration, but that makes the class declarations large and unwieldly.

More member functions

Last time we talked about accessor functions, which are one type of member function. There are also many other types of useful member functions. The constructor and the desreuctor are two very important member functions.

The Constructor member function

One special member function allows you to do work on the data as soon as your class is instantialted, the constructor. This function has no return value, not even void, and can be overloaded. The base constructor that is called automatically is the default constructor, it has no parameters. This allows you to set all the member variables to default types. Be careful, because this is not initalization, but just setting the values to default types. This means that you can not just set strings equal to constant strings, you need to use strcpy like in the accessor function from last time. An example class with constructors is shown below:
class box_car
{
private:
    double height, width, length;
    char SerialNumber[8];
public:
    box_car(); // The default constructor.
    box_car(double,double,double); // Another constructor
//  ...  The accessors go here
};

// The default constructor sets values that are reasonable.

box_car::box_car()
{
    height = 11.0, width = 9.0, length = 40.0;
    SetName("No name");
}

box_car::box_car(
    double initHeight, // Inital values that you can set when
    double initWidth,  //  using your new type.
    double initLength)
{
    height = initHeight;
    width  = initWidth;
    length = initLength;
    SetName("No name");
}
Now that we have our declarations and definitions of the constructors, how do we use them? Well the default constructor was already being used. The default constructor is used in the basic variable declaration step. In order to use a different constructor, you need to change the variable declaration a bit to make it look like a function call:
box_car car1; // Uses default constructor.
box_car car2(3.5, 9.0, 40.0); // uses other constructor.
box_car myBoxCarArray[6]; // Uses default constructor on each
                          // element of the array.
box_car * myBoxCarArray2[x]; // Uses default constructor on each
                             // element of the array.
We will look at how to use other constructors on individual elements of an array later. Much later.

What winston calls reader and writer functions are just accessor functions.

How to benifit from data abstraction

a.k.a. Why do we use classes? The first and most important element of data abstraction is that when using the accessor functions, you do not know what is happening. If the internals of the class change at a later point, as long as the "interface" remains the same the class can still be used for exactly the same purpose, in the same way, with no affect on the rest of your program. This is why you want to use accessor functions instead of just directly changing the member variables.

This is also why when you are creating a class you need to make constructor and accessor functions. If you hide all of the data behind these functions, you are said to be making a data abstraction layer. This is crucial to good "object oriented" programming.

Another advantage is that you can provide more functionality from your class by just adding more functions, without losing the ability to acces the old functionality. All of these points provide the following bullets:

  • Your code is easier to reuse.
  • Your code is easier to read.
  • You can easily augment what your classes provide.
  • You can easily improve the way your data is stored.