Gillius's Programming

Chapter I -- Introduction to OOP

Thinking in OOP

Moving into OOP is what changes programming from dechipherable code into real, understandable thought that is easy to understand. You have to keep in mind that the computer thinks in specifics. In fact so specific that the only thing the computer truely understands (if understanding is proper terminology) is "electrical signal on." Perhaps not even "off" as that is simply the absence of an "on," but that's a matter of philosophy.

Layering

You may wonder then, how, from this one simple concept can the computer generate programs as smart as a spell checker and worlds as complex as Quake III. The explanation is layering. Could you understand how a program could use a sequence of electrical signals to create numbers in binary, a base 2 system? Not too hard (assuming you know binary ;) ). So now the computer is up to the level of counting. From counting you could teach the computer to add a number by seven by telling the computer how to combine the singals (binary add), and then to multiply -- skip a few steps and you have a math wizard. If you've ever taken a physics class you know pretty much anything can be accurately modeled, or at least approximated, through some sort of equation.

When you have a base command set, you make new commands on those, and so on. The fallback from this is that after every "level," you lose a little efficently in the process (ever wonder why Windows is so much slower?). The library your compiler provides is mid-way or so in the scheme of things. Just one C++ line, cout << "Hello World!"; executes hundreds of instructions, perhaps more, by the time it reaches a level of the simplest instructions the CPU understands. And then you make your functions could use cout statement many times... Now you can see where those billions and trillions of calculations a second go!

Containership

Now you may wonder how this applies to programming in OOP. Well look at what's on your desk. A computer. Think about what parts make up the computer. You might list a keyboard, CPU case, monitor, mouse, printer, and such, but in essence to the computer you would be wrong. There is much more to it, so let's go deeper. Look at the keyboard. What parts make up the keyboard. A lot. Starting to sound a bit like The Matrix? But if you notice there are really a few TYPES of keys. Since all of the letter, number, function, cursor keys, and a few others are the same size, as far a programming is concerned these could be the same object, with a char type variable holding what that key does, and the whole set of keys are in an array, which is an element of the keyboard struct, which is an element of the computer struct. This method of looking at OOP is called containership.

Inheritance

Another method of looking at OOP, which is just as valid, is inheritance. And instead of looking from the big to the small, you look from the generic to the specific. Try to start as generic as common sense dictates. Let's use "vechicle" as an example. What do all vechicles have in common? They all have tires and engines right? Wrong. Helicopters are vechicles and don't have tires and glider planes don't have engines. The comptuer takes everything 100% literally, so you have to be as specific as possible when planning your programming project. All vechicles can move -- that's what makes them vechicles. Now in our "real world," this matters worth squat since all matter can move but for a computer an object that can move can do something, and anything that happens needs to be coded. To continue, think up more specific groups, like cars, which share tires, engines, and more, and even farther to say four-door and two-door, then to specific models like a Nissan Sentra, which has all of the previous features in common but has unique characteristics such as X horsepower and X size fuel tank.

The point of doing this is for breaking down many complex objects and tasks into simpler subgroups which can be programmed by themselves and then used in all objects following that one. For example you could program an engine then anything that has an engine in it will use that code when they run their engine.

Back to Top


Chapter II -- The Syntax of OOP

Prototypes

Now that you understand the concept it's time to get down to some real programming. The fundemental unit of OOP in C++ is called the class. A class works virutally identical to the struct in C, except in addition to variables (called members in OOP), it can also contain functions and subprocedures, which in OOP are called methods, and resemble the actions of the object. I know you are waiting to dig right into it, so let's look at the declaration syntax, or prototype of a class. Let's model a simple counting device as an example:

class Counter {
public:
  void Count();
  int  ReadDisplay();
private:
  int  CurrentCount;
};

Remember to add the semi-colon to the end of the class, just like a struct. Some compilers won't pick up this error directly and will put out some strange results.

Anything that goes under the "public:" is a member or method which can be accessed freely from a program, exactly as if the class were a struct, whereas anything private cannot be accessed by the program. Here are a few ways to use this class. Notice that classes use the dot operator just like the structs and act just like structs except with functions now:

Counter obj;    //declare just like a struct
obj.Count();    //will call the Count in the class, which will make
                // the counter count
int var = obj.ReadDisplay();
                 //"interact" with the counter by getting some
                 // information from it
var = obj.CurrentCount;
                 //you can't do this since CurrentCount is private!

Data Hiding

From first glance you may assume that anything after "public:" is a function and "private:" is a variable, and this is the case most of the time, but not always. Anything may go under either public or private, and either public or private can come first. You may also wonder why you would want to keep information from the program (called data hiding). The main reason for this is to get the extra variables out of the way. Normally, if a class is programmed correctly, all interaction should be through the methods, rather than through the members. There are many more very important reasons for this (for example changing the way the class works without changing the actions), which will be explained in-depth later, but for now try to keep only the essential parts of the class public.

Our counter example uses data hiding. The CurrentCount is hidden, and protected, from the programmer making direct adjustments. Instead the counter should Count(), and the user should ReadDisplay() to see how many times the counter has counted.

Defining Functions

Now that we know how to declare the functions and use them, we need to write the actual code. Some may wonder why not write the code first then organize it. Well the best way to program is decide what you want and how you will be using it first, then create a "skeleton" code. First thing is to prototype all of the functions that make sense, on the abstract level (for example a person can walk, jump and play), then define functions for those actions. Create empty functions by those names, then fill in the "skeleton." You'll find that doing it this way is a much cleaner, and more directed, approach, since you write code in small, easy-to-understand, chunks at a time. So let's create our "skeleton." Take notice of how class methods are defined:

void Counter::Count() {
  //This function will increment the CurrentCount
}
int Counter::ReadDisplay() {
  //This function will return the current count and display it
}

The Scope Resolution Operator, the ::, tells the compiler that the function belongs in the MyObject class, and allows the programmer to define this anywhere in the program, just as with normal functions. Now that we have our "skeleton" made, and have decided exactly what the functions should do, it is time to write the code. Notice that variables in the class, even the private ones, are readily accessable. This is because they were declared in the Counter scope, which these functions are part of. A scope is generally defined as code inside a set of brackets, but also applies to the entire class as a whole as well.

void Counter::Count() {
  CurrentCount++;
}
int Counter::ReadDisplay() {
  cout << "The Counter Reads: " << CurrentCount;
  return CurrentCount;
}

And now our counter is ready to be used any way we want to use it. We could even make an array of counters (Counter Counters[10]) to keep track of multiple counts. Every possible thing you can do to a struct works just the same on a class.

Defining Small Functions

The method shown above is the most common method used, but if you have small functions that are only one line, or perhaps two very small lines, sometimes they will be defined inline, with the declaration. When a function is inline, the compiler places copies of the code in each area it is executed, to allow for the processor to execute a short jump command, which saves 16 bits of data. This may not sound like a big deal, and you are right, espically in today's computing age. However, for very tightly polling loops which are executed millions of times per second, a simple one-line function is best made inline.

For all intents and purposes of the level of programming you are at, this is certainly not anything to worry about, until you start programming hardware level procedures, and by the time you get that far you will understand the need of inline. But for now, you should understand how this looks, and it can also come in handy with writing functions like Count() and another version of ReadDisplay() which will be shown:

class Counter {
public:
  void Count() {CurrentCount++;}
  int  ReadDisplay() {return CurrentCount;}
private:
  int  CurrentCount;
};

That is a fully-functioning counter class. For functions that small, inlining them is encouraged. But for anything more than a simple one liner, it's best to use the traditional method, or you will just make the code harder to read, bigger, and slower in executing.

Using the Code

The best way to use a new class is to create a source code file for each class (or group of classes), and a header file for each source code file. Include the source in the entire project, and with every other source file that may want to use the class, include its corresponding header file. For example for this class I would create the declaration for the class in a file called "COUNTER.H", and place the defined functions in a file called "COUNTER.CC" (or "COUNTER.CPP", depending on the extension your compiler uses).

Syntax Quibbles

Syntax Quibbles on class: The indenting and order of the public and private keywords shown above is only my personal preferance. A lot of times, private is shown first because programmers are used to declaring varaibles before writing code, rather than vice-versa, and this is okay; however, the user of the class or library must skip past all of the private segment before reaching the public segment, the part they need to see to use the class.

Also, some programmers will indent the two keywords once and indent the declarations twice. All of these forms of writing the class structure are acceptable. Pick the one that is best for you. Below is a chart showing a few ways to format a class:

class Counter {
public:
  void Count();
  int  ReadDisplay();
private:
  int  CurrentCount;
};
class Counter {
private:
  int  CurrentCount;
public:
  void Count();
  int  ReadDisplay();
};
class Counter {
  public:
    void Count();
    int  ReadDisplay();
  private:
    int  CurrentCount;
};

Back to Top

Proceed to Chapter III - Using OOP