Neil's C++ Stuff



C++ Classes Tutorial

I actually was not planning in the least to do a tutorial on classes. My main reason is that IMHO classes are slightly tougher to comprehend or at least use effectively than pointers. But don't be intimidated, I now will attempt to ease your knowledge towards OOP and classes. I have had many questions that I had difficulty answering appropriately so I figured I could write better than speak and thus I began this page.

As always I would like to take the time to mention that this page was not written to glamourize myself or anything else. This page was written for you, my classmates, my friends. If there is anything that you don't understand then contact me. If you understand one of the following concepts and think you could explain it better, contact me and I will put that up here fully crediting you. If you have further inquiries that I might seek to squelch, contact me. And if you think I'm a smelly pig that deserves to rot in hell, don't contact me but be sure to pray for my soul.

Relation Between class and struct

Classes at their simplest are slightly related to the worn old struct. In fact if you wanted to use a class instead of a struct but don't want to have to change any of your code you could do what I do to the date struct (below).

struct date
{
int year, month, day;
};

And make it look something like:

class date
{
public:
  int year, month, day;
};

Of course this is blasphemous coding and if any stick-up-the-ass C++ programmer catches you doing this then he'll have your head. But for our purposes this will do just fine and I'll build on the above example in the succeeding parts. If you don't know how to declare a structure type or know how to use a structure variable then please get to that first.

Constructors: Why Use Them?

A constructor is a function that has the same name as the class it is declared in. So for our date class the constructor function would be called date as well. When you create an object based on a class the constructor function is called. For example if we have a class called date (yes, I'm going to wring every last ounce of usefulness out of crummy ol' date) and we create an object called dt:

date dt;

In doing the above and upon creating the object known as dt, dt's constructor function date() is called (only if it exists of course). To see this in action try the following snippet of code:

/* -example 1--------------------------------------------------------------- */

#include <iostream.h>

class date
{
  public:
    date()
    {
      cout << "We have just created an object based on this (date) class!"
           << endl;
    }

    int year, month, day;
};

void main()
{
  date dt;
}

/* ------------------------------------------------------------------------- */

When you type the above in and run it you will get the message "We have just created an object based on this (date) class!". So you see, when we created the object dt that function was automatically called as well. Many people have asked me the use of this, so I will try to explain. The constructor function (date() in this case) is used mainly for resetting the variable members of the class. In the above example I could have shown this by putting the following line in the function:

year = 0; month = 0; day = 0;

Making all of our object's variables zero is slightly pointless because newer compilers do this automagically (like our beloved MSVC *bleck*). It'd be more appropriate to set purposeful defaults. Something like:

year = 1998; month = 10; day = 6;

This sets the values to something more appropriate (the day I wrote this tutorial). Slightly more useful than just zeroing them out. Or if we were designing this poorly (which I often do while learning new things!) we could do something like:

cout << "Input a year: ";
cin >> year;
cout << "Input a day: ";
cin >> day;
cout << "Input a month: ";
cin >> month;

You get the idea. Its use is to put initial values in the object's variables. That way we don't always start with ugly ol' zero or (in the case of more optimized compilers) total garbage. By this point you should understand how to make a simple class and a simple constructor function. If not tell me so I can write the above in a more clarifying manner.

Constructor Functions w/ Parameters

Here I present to you the latest stumbling block which has been reaking havoc on the sanity of my fellow classmates. I will now attempt to still those unearthly bowel movements and calm those severly played nerves. I'll keep using the date example because by this point you should be fairly used to its aging charm.

Let's say (using our previously example of the date class) that we wanted to set its variables when we create the object. And we want these values to be different each time. Let's say we want to create two objects (based on the date class): bob_dob and mary_dob. And we know when we're coding this that bob_dob should be 8-19-1979 and mary_dob should be 11-28-1976. Since we already know what the values of these objects should be, making the user type them in would be tiring. One way we could do this is by changing each of the variables individually:

date bob_dob, mary_dob;

bob_dob.year = 1979;
bob_dob.month = 8;
bob_dob.day = 19;

mary_dob.year = 1976;
mary_dob.month = 11;
mary_dob.day = 28;

This is obviously profusely tiring to type in and just think if we wanted to add jae_dob or nurit_dob?!?! Yes, you're probably thinking that by that time you would no longer have fingers but gnarly taloned paws. Fear not, there is a simple answer to this (not the only one, but hey, I'm trying to have a point to this).

What we can do is make a constructor function that takes three parameters, one for each of the variables year, month, and day. And in this constructor we could set the values of each of the variables to the parameter's values. So if we pass (1979, 8, 19), then it will place those values appropriately (year would become 1979, etc.). Now, I know what you're thinking? What could this wonderful invention cost? 10,000 dollars? No, just two easy steps my friend.

First we actually have to write a constructor function that takes three parameters, each of them integers. We already know how to write just a normal function that takes three integer parameters so here I just apply the same concept except the name of the function is (of course) the same as the name of the class: (note! constructors never have a return value like void or int because they can never return anything)

date (int y, int m, int d)
{
  year = y;
  month= m;
  day  = d;
}

On to the second part; now if we were to call this function like a normal function you could call it like:

date(1979,8,19);

But of course you can't call a constructor function like this (because constructors aren't necessarily "normal" functions). Remember back (I know its sometimes painful) that to call a constructor you simply create an object. So you may be thinking you can do something like this:

date dt;

Getting closer, but still wrong. You see there are no parameters being passed to the constructor function and poor ol' MSVC gets upset when you try that. To pass parameters to the constructor you enclose them in parenthesis () and put them after the name of the object, but before the semi-colon:

date dt(1979,8,19);

Wah la! MSVC will like you for doing this. Before I go into deeper explanation let me give you some sample source code (same as before but with this new constructor and bob_dob and mary_dob):

/* -example 2--------------------------------------------------------------- */

#include <iostream.h>

class date
{
  public:
    date(int y, int m, int d)
    {
      year = y;
      month= m;
      day  = d;
    }

    int year, month, day;
};

void main()
{
  date bob_dob(1979,8,19);
  date mary_dob(1976,11,28);
}

/* ------------------------------------------------------------------------- */

Nifty, eh? Short and sweet. Also, remember how if we wanted to declare two integers we could simply say:

int x,y;

Well, in our situation we could have done the same thing (but I am trying as hard as possible to avoid unecessary confusion). It would've looked like this:

date bob_dob(1979,8,19), mary_dob(1976,11,28);

Even shorter! I can tell that to avoid typing, a lot programmers use even crazier short-cuts.

Okay, in the above example there is a line that reads date bob_dob(1979,8,19);. It breaks down like this:

date symbolizes that we are going to create an object based on this class definition. Simply speaking we're going to make something.
bob_dob is the name of the object that we're going to create.
( also known as the infamous and often forgotten left parenthesis tells us that we're going to be passing some parameters.
1979, tells us that the first parameter (y) in the constructor function will be this value.
8, tells us that the second parameter (m) in the constructor function will be this value.
19 tells us that the third and last parameter (d) in the constructor function will be this value.
) says that we're done passing parameters and there ain't gonna be no more of that.
; of course states that this statement is finished.

And now at this point during the execution (or running) of the program you will be inside the constructor function. Inside this function the parameters have been set so that y is 1979, m is 8, and d is 19. The following statements ensue:

year = y;
month= m;
day  = d;

Therefore because our parameter variable y has been set to 1979, the value of variable member year becomes 1979 as well (year = y; or in this case it might look like year = 1979;). You probably get what happens next and by the time we reach the end of the function year has been set to 1979, month has been set to 8, and day has been set to 19.

Ta da! We have now made and used a constructor that has parameters. Now, if you previously had trouble completing the square class you now may have the weapons to conquer it. Good luck! Later on in this section I'll get into more class ding-bat stuff so check back later! Hasta la pasta.

Destructors: Clean Up Your Messes

A deconstructor is exactly that, a tool to make your classes automagically clean up their own messes when they are destroyed. Deconstruction is as in taking apart before obliberating.

Most of the time, especially in the cases of this tutorial, you will not need a deconstructor because we only deal with simply variables. The times when you actually need them is when you use dynamic memory allocation, mess with things that need to be set back when your done, etc.

Remember how constructors are called when you make an object based on your class? Destructors in contrast (and brightness? *pun pun*), are called when the object is destroyed. Local variables are destroyed at the end of the function they were created in:

void just_a_func()
{
  int local_var; // <--------- we create local_var

  // we do something here with local_var

} // <------------------------ local_var is destroyed at this point

If local_var had been an object based on a class, its constructor would have been called where we created it, and its destructor where it was destroyed (at the end of the function). When the destructor is called you can be sure that your object is going bye bye, and you use the chance to fix all the misgivings your object may have wreaked during its life.

Destructors: An Actual Function

To declare a destructor function is similar to declaring a constructor function. The destructor's name should be exactly the same as the name of the class (like a constructor), however it should also be preceded by a tilde (~). So for our class date the destructor prototype would be:

~date();

Pretty simple. The biggest difference (that I see) between constructors and destructors is that the latter cannot have any parameters. I mean seriously, what and how are you going to pass things to something that's on its way to doom. Its like throwing a rope over a cliff after someone has fallen. It's too late!

But enough talk, let's see a working destructor in action:

/* -example 2--------------------------------------------------------------- */

#include <iostream.h>

int num_date_objects;     // global variable to keep track of the number
                          // of 'date' objects

class date
{
  public:
    // constructor!
    date(int y, int m, int d)
    {
      year = y;
      month= m;
      day  = d;

      num_date_objects++; // add one to the number of date objects, this
                          // number will be THIS object's id number
      id = num_date_objects;

      cout << "Calling constructor, creating date object #" << id << "!"
           << endl;
    }

    // destructor!
   ~date()
    {
      cout << "Calling destructor!  *AWOOGA* *AWOOGA*!  date object #"
           << id << " has perished!" << endl;
    }

    int year, month, day, id;
};

void main()
{
  num_date_objects = 0;

  date bob_dob(1979,8,19);
  date mary_dob(1976,11,28);
}

/* ------------------------------------------------------------------------- */

After running the above you'll get the following output:

Calling constructor, creating date object #1!
Calling constructor, creating date object #2!
Calling destructor! *AWOOGA* *AWOOGA*! date object #2 has perished!
Calling destructor! *AWOOGA* *AWOOGA*! date object #1 has perished!

Note the order in which the objects are destroyed. It is the exact opposite of the order in which they were created. You know there's a nice acronym that stands for something that relates to this, but by god I totally forgot what it was.

Recently several people have sent in the name of this acronym and therein forced me to update this. The acronym is FILO: First In Last Out. Thanks to all of you who pointed this out!

Just remember that though. The first object you create will be the last one destroyed (in this particular function). Note that at the end of main, the destructors for all global objects are called as well.

Class Members: public, protected, and private

I'll try to explain what these are as well as their purpose. Note that in my humble opinion I don't regard them very important or necessary when used in something like the square class.

You see classes could be something like animals. Some animals every part of them is public. You can poke and prod them in any way you like and they don't really give a damn. However, on the other hand there are animals that care what you can touch and what only they themselves can. Many of these animals I have been known to refer to as "humans". I know this is a new concept, but bare with me.

Humans have parts that generally speaking you can touch without them beating the crap out of you or calling their S.O. (or police) to beat the crap out of you. These are things like hands, hair, or toe nails (public). However there are parts that they jealously guard (protected) that only people close to them can touch like legs, noses, or elbows. And lastly there are those parts that they cover with fig leaves that only they (or their "better half") have access to. We call these "privates".

As far as classes go when you create an object (date dt;) then all of its public members can be accessed from the function you created it in. For example when we created dt in main() we had access to its public members like year or day. We could have accessed them by joining the name (dt) and the variable member (year, month, or day) with a period:

void main()
{
  date dt;
  dt.year = 1998;
  dt.month= 10;
  dt.day  = 6;
}

We could use these as such because they were deemed public in the date class. Had we listed them under private or protected we would not be able to do this (compiler would puke).

protected class members can only be used inside the class they were declared in or derived/inheriting classes (if you don't know class inheritance yet then don't worry too much about the difference between protected and private ... yet). So if we derived a class called astro_date from the class date, then all the protected members of date would be accesible by astro_date's functions.

private class members on the other hand, can only be accessed by the class they are listed in. Not in derived classes or anything, JUST the class they are listed in (drilly this into your head). private means private as in, don't show or allow access to anyone other than myself (or better half).


Contact

Comments or questions? Email me at webmaster@neilstuff.com.