Why Program With Objects?

It is good packaging:

  1. It keeps the data and basic functions needed to change the data together.

  2. It allows you to hide (protect) parts of the object from the user

  3. It allows you to reuse the object to more easily build related objects.

Motivation by example: Consider the problem of dealing with screen coordinates on a computer display.

What do you need to know about these coordinates?

To make simpler, let's deal with a monochrome display (blank and white).
So we need three variables to keep the information. How about
rainbow.gif (2243 bytes)

   int number1;
   int number2;
   int number3;

rainbow.gif (2243 bytes)
Not too good, huh? WHY is this a bad choice?
rainbow.gif (2243 bytes)

   int x;
   int y;
   int display;

rainbow.gif (2243 bytes)
Well, it is better but not clear that these three go together to define a single screen coordinate.
Also, what if you wanted a second Coordinate (to represent the end points of a straight line)?
Let's package them a little differently.
rainbow.gif (2243 bytes)

   struct Coordinate {
      int x;
      int y;
      int display;
   }

rainbow.gif (2243 bytes)
Now it is clear that the three variables go together and they are parts of a bigger structure called "coordinate".
Also, now is is possible to have many coordinates, for example
rainbow.gif (2243 bytes)

   Coordinate point1;
   Coordinate point2;

rainbow.gif (2243 bytes)

The declaration of the struct Coordinate introduces a new collection of things into the program of which we you can many instances (represented as individual variables of that structure type). To set values in an instance, you use the dot '.' operator. For example
rainbow.gif (2243 bytes)

   point1.x = 30;
   point2.display = 0;
   cout << point1.x;

rainbow.gif (2243 bytes)
But there are still problems.
What if you want to make sure that the programmer using this structure does not put ridiculous values in the fields? Say that the only values that make sense for "display" are 0 for black and 1 for white, and that the x and y coordinates cannot be negative or greater than 1000?
Can you control the programmer so that they don't mess up what the values mean?
Well you can if you use a generalization of structures called classes. Now you not only package the data together, but also the functions that changes the data which you write to make sure that no bad values are put in the data fields.
rainbow.gif (2243 bytes)

   class Coordinate {
      void setX(int xValue) {
         if(xValue < 0) xValue = 0; // clip values
         if(xValue > 1000) xValue = 1000;
         x = xValue;
      } 
      void setY(int yValue) {
         if(yValue < 0) yValue = 0; // clip values
         if(yValue > 1000) yValue = 1000;
         x = yValue;
      } 
      void setDisplay(int dValue) {
         if(dValue < 0) dValue = 0; // clip values
         if(dValue > 1) dValue = 1;
         display = dValue;
      } 

      int x;
      int y;
      int display;
   }

rainbow.gif (2243 bytes)
Now we have made an object class out of the coordinates. To get individual object instance, we just do as we did before.
rainbow.gif (2243 bytes)

   Coordinate point1;
   Coordinate point2;

rainbow.gif (2243 bytes)
To set the values safely, you can use the newly provided functions.
rainbow.gif (2243 bytes)

   point1.setX(30);
   point2.setDisplay(45); // a mistake but it will be fixed
   cout << point1.x;

rainbow.gif (2243 bytes)
Are we there yet? no but we are close.
First of all, the above code won't work in C++ and it is for a good reason.
If we allow access to point1's 'x' value (like we did to print it out), then another program could just set the value directly, like we did with the structure implementation, and by pass the safe function 'setX' altogether. So if we really want to protect the values of 'x', 'y' and 'display', we need to make them 'private'. This principle of hiding information from programs is an important part of object oriented design. In fact, unless you specify otherwise, all members of a class (functions and data) are private by default.

Of course if everything is private, then the class cannot be used by anyone. So something's have to be public (like 'setX'). This is done by declaring certain members of the class to be 'public' and others 'private'. Now we have
rainbow.gif (2243 bytes)

class Coordinate {
    public:
      void setX(int xValue) {
         if(xValue < 0) xValue = 0; // clip values
         if(xValue > 1000) xValue = 1000;
         x = xValue;
      } 
      void setY(int yValue) {
         if(yValue < 0) yValue = 0; // clip values
         if(yValue > 1000) yValue = 1000;
         x = yValue;
      } 
      void setDisplay(int dValue) {
         if(dValue < 0) dValue = 0; // clip values
         if(dValue > 1) dValue = 1;
         display = dValue;
      } 
   private:
      int x;
      int y;
      int display;
}

rainbow.gif (2243 bytes)
Now what? Well, we can safely set the values of the object, but we can ever see them again! We could make the data members public also, but this defeats the security we want in setting their values.
What we need are public functions which will let use see the values.
rainbow.gif (2243 bytes)

 

class Coordinate {
    public:
      void setX(int xValue) {
         if(xValue < 0) xValue = 0; // clip values
         if(xValue > 1000) xValue = 1000;
         x = xValue;
      } 
      void setY(int yValue) {
         if(yValue < 0) yValue = 0; // clip values
         if(yValue > 1000) yValue = 1000;
         x = yValue;
      } 
      void setDisplay(int dValue) {
         if(dValue < 0) dValue = 0; // clip values
         if(dValue > 1) dValue = 1;
         display = dValue;
      } 
      int getX() {
         return x;
      }
      int getY() {
         return y;
      }
      int getDisplay() {
         return display;
      }
   private:
      int x;
      int y;
      int display;
}

rainbow.gif (2243 bytes)
Since the member functions belong to the class, they are allowed to access the private data members.
Does this seem like a lot of work to get a little safety? Perhaps, but this is a simple example. As obejcts get more complicated, it is nice to have everything packaged and protected. There will be more to say about protected both data and function members later, when we talk about friends and inheritance.

 

Here are some general guidelines that we used in this example that apply to most classes:

  1. All Data Members should be private (so a clumsy programmer cannot put inconsistent information there).
  2. For every private data member, there is usually a 'set' function and a 'get' function

Here is a complete program which uses this class.
You can get your own, compilable copy by clicking here.

rainbow.gif (2243 bytes)

 

class Coordinate {
public:
      void setX(int xValue) {
         if(xValue < 0) xValue = 0; // clip values
         if(xValue > 1000) xValue = 1000;
         x = xValue;
      } 
      void setY(int yValue) {
         if(yValue < 0) yValue = 0; // clip values
         if(yValue > 1000) yValue = 1000;
         x = yValue;
      } 
      void setDisplay(int dValue) {
         if(dValue < 0) dValue = 0; // clip values
         if(dValue > 1) dValue = 1;
         display = dValue;
      } 
	  int getX() {
         return x;
      }
      int getY() {
         return y;
      }
      int getDisplay() {
         return display;
      }
private:
      int x;
      int y;
      int display;
   };
#include <iostream.h>
void main() {
	Coordinate p1;
	Coordinate p2;
	p1.setX(37);
	cout << p1.getX();
}