00:00
00:00
Newgrounds Background Image Theme

Someone gifted SkilledFella supporter status!

We need you on the team, too.

Support Newgrounds and get tons of perks for just $2.99!

Create a Free Account and then..

Become a Supporter!

C++: A Full Tour Of Oop

1,227 Views | 12 Replies
New Topic Respond to this Topic

C++: A Full Tour Of Oop 2007-08-06 17:42:04


C++ Main: Where BASIC dies.

Intro to OOP

Hey guys. Today I will be writing a tutorial on Object Oriented Programming(OOP) in C++. This
will hopefully help someone learn the heart of C++ and will help me reinforce my own knowledge.
The three major concepts of OOP are: encapsulation, inheritance, and polymorphisms. There's a
mouthful! This tutorial will explain all three.

Encapsulation

Encapsulation in programming refers to the containment of information. In OOP, you want to
create objects that contain information about something in them. This information should be
visible only to that class. This is the basis of encapsulation. In other words, all information in an
object should ONLY be visible to that object, no other object should be able to see them.

Here is an example of a program that does not demonstrate encapsulation:

#include <iostream>
using namespace std;

class NoEncap{

public:
-----int x;

};

int main(){
------NoEncap ob;
------ob.x = 42; //Valid
------cout<< ob.x <<endl; //Valid
------cin.get();
------return 0;
}

In the above example, the instance variable 'x' is declared public by the public label.The public label
means that all variables after this label (in this case only x), will be openly accessible to all other
objects in your program. This is demonstrated in the example. In main, I can access x from ob using
the dot operator. This is not good because I don't want to be able to change the state of my object
(which is determined by those instance variables), without using the object's methods. This is
encapsulation. In OOP I want to encapsulate all variables of an object so that they can only
modified by that object's methods.
Here is an example of the same program above, that follows
encapsulation:

#include <iostream>
using namespace std;

class Encap{
-----int x; /*x is now private, because information in classes are private unless specified otherwise*/
public:
-----int getX() { return x; }
-----void setX(int newX) { x = newX; }
};

int main(){
------Encap ob;

------ob.x = 42; //Invalid. Causes an error!
------cout<< ob.x <<endl; //Invalid. Causes an error!

------ob.setX(42); //Valid, while x is declared private, setX and getX are declared public
------cout<< ob.getX() <<endl; //Also valid. getX() is public and therefore accessable outside itself

------cin.get();
------return 0;
}

Notice, now x is declared as a private variable and the two new methods are public. In this way,
I have access to the methods that alter my object's variables, but I don't have direct access to the
variables themselves.
Since the x is declared private, only methods from inside the object can
access it. This is why getX() can access x without a problem. private makes information invisible to
everything outside the class.

In a well developed object, the only public methods are those that the programmer needs to alter
the object. The rest should be private. Take this next example. I will make a simple class that takes
two numbers and adds them.

#include <iostream>
using namespace std;

class EncapPlus{
-----int x;
-----int y;
-----//Both x and y are private variables
-----int calculateSum(){ //This is a private method. It can only be called inside the class.
----------return x + y;
-----}

public:
-----void setXY(int newX, int newY){
----------x = newX;
----------y = newY;
-----}

-----int getSum(){
---------- int theSum = calculateSum(); //Allowed because call is made from inside EncapPlus
----------return theSum;
-----}

};

int main(){
-----EncapPlus obj;

-----obj.setXY(4,16);
-----cout<< obj.calculateSum() <<endl; //This line is an error! calculateSum is private!
-----cout<< obj.getSum() <<endl; //Valid because getSum() is public.

-----cin.get();
-----return 0;

}

Notice that calculateSum is private, and therefore can only be called by methods declared within
EncapPlus. The only public methods in this class, are the ones the programmer will use to
manipulate the class. This is the heart of encapsulation

Encapsulation is important because it lets you create easy to use classes. As a programmer, you do
not need to know how the class does what it does. You simply need to know the interface of
the object. By interface, I mean the public methods the programmer will use to manipulate the
object. For instance, in the above example, I would not need to know how given two numbers,
EncapPlus adds two numbers. I would only need to know that if I call getSum(), I will get the sum.
This seems redundant with addition, but let me give you another example. Say I'm making a game
of asteroids. I need to draw a Ship on the screen. I would make a public method called makeShip(). I
would not need to know how the ship is made, I would only need to know that when I call
that interface method, a ship will be made.

<continued on next post...>

Response to C++: A Full Tour Of Oop 2007-08-06 17:44:52


Inheritance

Inheritance refers to one object inheriting properties from another object. Inheritance tries to
establish an "is-a" relationship. This is a really easy concept to understand. Let me give you an
example.

An apple is a fruit. A fruit is a food.

Do you see how the relationship goes from most general (food) to most specific (apple). Think of
about it a little more though. A fruit has all the characteristics of a food. In turn, an apple has all
the characteristics of an fruit. Think about this common phrase:
All apples are fruits, but not all fruits are apples.
Since all apples belong to the fruit family, they are all fruits, but not all fruits are apples. Only some
are. I hope that makes sense.

Back to inheritance in C++. When we use inheritance, we try to establish families of relation like
above. For instance, let's say I have an Animal class. All animals have a names and make noises, so
here would be my animal class:


class Animal{
-------string name;
public:
-------string getName(){ return name; }
-------void setName(string newName) { name = newName; }
-------void makeNoise() { cout<<"ANIMAL NOISE!!!!!!"<<endl; }
};

Now lets think about a kind of animal. Felines. This is a family of animals like cats, tigers, lions.
Lets say(for simplicity), that all Felines have everything that animals have + claws. Now we could
write out a new Feline class with containing everything that Animal has, OR we could use
inheritance to inherit the things that Animal and then add claw info. Take this example:


class Feline : public Animal {
------int clawLen;
public:
------int setClawLen(int newClawLen) { clawLen = newClawLen; }
------void scratch() { cout<<"OUCH"; }
};

Note the use of the colon to inherit all the traits of Animal. The public means that all the public
methods of Animal, will become public methods of Feline. Everything private, will remain private.
There is also private and protected specifiers, but they are outside of the scope of this tutorial.
Now Felines all have a name variable (even thought it is not explicitly defined in Feline), methods to
access the name, and a makeNoise() method. Those are the traits that Feline derived(or inherited)
from Animal. Along with those common traits, Feline defines several extra goodies (clawLen).
Note that the Animal class does not have clawLen, setClawLen(int newClawLen), or sratch(). These
are added only for Feline.

The properties (the methods and variables) of Animal were inherited to Feline

Now let's examine two level inheritance. Say that I now need a type of Feline, cat. For simplicity
sake, lets say that a cat can be either an indoor cat or outdoor cat. Here's an example:


class Cat : public Feline{
-----bool indoorCat; //true if the cat is an indoor cat
public:
-----bool isIndoorCat() { return indoorCat; }
-----void setCatStatus(bool newStatus) { indoorCat = newStatus; }
}

In the above case Cat contains all the properies of Animal AND Feline, as well as Cat specific
details (ie, indoorCat)

<continued on next post...>

Response to C++: A Full Tour Of Oop 2007-08-06 17:48:49


Note that Feline does not contain anything that Cat defines explicitly
(indoorCat, isIndoorCat(), and setCatStatus() ).
Using C++'s inheritence system, we just developed the following is-a relation:

A cat is a Feline. A Feline is a(n) Animal

This is a class hierarchy. We developed a specific class (Cat), by using properties from more
general classes (Feline, and Animal).
Note that all three classes can be used as objects just like any other class.

Polymorphism

Polymorphism sounds like a hard concept. To simplify it, just think of the following phrase: One
interface, multiple methods. In polymorphisms, we try to create methods that will do something.
These methods will be able to act slightly differently based on what kind of data they are dealing
with, but they are all under the same name. One interface, multiple methods.
C++ supports two types of polymorphism. Compile time and run time. Compile time polymorphism
is accomplished by function overloading. It is not related to OOP, so it will not be talked about in
this article. Run-time polymorphism is based on OOP.

Let's use the previous Cat-Feline-Animal hierarchy as an example of run-time polymorphism. Recall
that Animal had a method called makeNoise(); that outputted "ANIMAL NOISE!!!!!!" to the screen.
Take this following code snippet as an example. Note: all the classes used are those developed
above.

int main(){

-----Animal sexyAnimal;
-----Feline sexyFeline;
-----Cat sexyCat;

-----sexyAnimal.makeNoise();
-----sexyFeline.makeNoise();
-----sexyCat.makeNoise();

-----return 0;
}

The output of the above program would be:


ANIMAL NOISE!!!!!!
ANIMAL NOISE!!!!!!
ANIMAL NOISE!!!!!!

What if I wanted to make it so that Felines and Cat's made thier own noise. How would I do that?
Run-Time Polymorphism bitches. That's how. I can overload makeNoise() when I inherent the
Animal class. By overload, I mean write a new version of makeNoise(). It will have the same name.
To do this, I will need to declare makeNoise() in animal as a Virtual function using the virtual
function. This tells the compiler that makeNoise() will be overloaded in the classes that derive it.
Let's look at the new class Hiearcy:

class Animal{
-------string name;
public:
-------string getName(){ return name; }
-------void setName(string newName) { name = newName; }
-------virtual void makeNoise() { cout<<"ANIMAL NOISE!!!!!!"<<endl; }
};

class Feline : public Animal {
------int clawLen;
public:
-------virtual void makeNoise() { cout<<"FELINE NOISE!!!!!!"<<endl; } //OVERLOAD
------int setClawLen(int newClawLen) { clawLen = newClawLen; }
------void scratch() { cout<<"OUCH"; }
};

class Cat : public Feline{
-----bool indoorCat; //true if the cat is an indoor cat
public:
-------virtual void makeNoise() { cout<<"CAT NOISE!!!!!!"<<endl; } //OVERLOAD
-----bool isIndoorCat() { return indoorCat; }
-----void setCatStatus(bool newStatus) { indoorCat = newStatus; }
}

Now, I have a specific implementation of makeNoise() for each class in my hiearcy. How will the
compiler know which type to call though? Through pointers. More specifically, base-class pointers.
A base class pointer is a pointer the points to an object of type <baseclass>, where baseclass is the
class that is derived from. What is the base class in our case? If you said Animal, you win! lol
Here is an example of a base class pointer:

Animal *basepnt;

Note that a base class pointer can point to any object that is derived from it. In this case, this
means that a pointer of type Animal can point to an object of Feline type and Cat type. For instance,
the following is valid:

-----Animal *basepnt;

-----Animal sexyAnimal;
-----Feline sexyFeline;
-----Cat sexyCat;

-----basepnt = &sexyAnimal;
-----basepnt = &sexyFeline;
-----basepnt = &sexyCat;

Although a baseclass pointer can point to any derived class, a dervied class pointer can not point to
a base class. For example, the following is invalid:

-----Feline *pnt;

-----Animal sexyAnimal;
-----Feline sexyFeline;
-----Cat sexyCat;

-----pnt = &sexyAnimal; //INVALID!
-----pnt = &sexyFeline; //VALID
-----pnt = &sexyCat; //VALID

Note, since Cat is derived from the type of our pointer(Feline), we can point to it. Animal however,
is not deceived from Feline (in fact Feline is derived from Animal), so our Feline type pointer cannot
point to it.

Now back to how the compiler knows what version of makeNoise() to call. The compiler will
determine which version to call based on what the base-class pointer is currently pointing to. Take
this as an example:

int main(){
-----Animal *basepnt;

-----Animal sexyAnimal;
-----Feline sexyFeline;
-----Cat sexyCat;

-----basepnt = &sexyAnimal;
-----basepnt->makeNoise();

-----basepnt = &sexyFeline;
-----basepnt->makeNoise();

-----basepnt = &sexyCat;
-----basepnt->makeNoise();

-----cin.get();
-----return 0;

}

The output from the above program is:


ANIMAL NOISE!!!!!!
FELINE NOISE!!!!!!!
CAT NOISE!!!!!!!!!

Bingo! Exactly what we wanted. We used one interface ( makeNoise() ), to do slightly different
things. That is polymorphism.

The End

Hope this tutorial helps someone. Please give me feedback on how I did. Hopefully I didn't mess
something up. Thanks for your time.

Response to C++: A Full Tour Of Oop 2007-08-06 18:31:42


Stealing tutorials is illegal

Response to C++: A Full Tour Of Oop 2007-08-06 18:33:29


At 8/6/07 06:31 PM, thingie-348 wrote: Stealing tutorials is illegal

Sorry, wrong window :)

Response to C++: A Full Tour Of Oop 2007-08-06 18:37:31


At 8/6/07 06:33 PM, thingie-348 wrote:
At 8/6/07 06:31 PM, thingie-348 wrote: Stealing tutorials is illegal
Sorry, wrong window :)

lol okay. This thing is not stolen.

Response to C++: A Full Tour Of Oop 2007-08-06 20:46:03


Nice job!

Response to C++: A Full Tour Of Oop 2007-08-06 21:28:34


*grins over from the VB camp* Wow ... not bad ... OOP rocks!

Response to C++: A Full Tour Of Oop 2007-08-06 21:42:39


At 8/6/07 09:28 PM, C4Cypher wrote: *grins over from the VB camp* Wow ... not bad ... OOP rocks!

I don't know how you VB users survived without pointers and OOP for so long :p

Response to C++: A Full Tour Of Oop 2007-08-07 06:22:35


unless my eyes decieve me, you didn't mention anything to do with constructors/destructors :/

Response to C++: A Full Tour Of Oop 2007-08-07 13:29:04


At 8/7/07 06:22 AM, dELtaluca wrote: unless my eyes decieve me, you didn't mention anything to do with constructors/destructors :/

Yea, I didn't. I only covered the three major topics of OOP. I figured that readers would have previous C++ knowledge. Especially in things like pointers and basic class design.

Response to C++: A Full Tour Of Oop 2007-08-07 13:42:18


no but they are to do with inheritance, i.e. calling super class constructor etc. like:

class c1{
public:
int x;
c1(const int & X) { x = X; }
};

class c2 : public c1{
public:
int y;
c2(const int & X, const int & Y):c1(X){y = Y;}
};

Response to C++: A Full Tour Of Oop 2007-08-07 13:48:32


At 8/7/07 01:42 PM, dELtaluca wrote: no but they are to do with inheritance, i.e. calling super class constructor etc. like:

Oh snap. Yeah, I completly forgot about passing parameters to super class constructors. Dammit. Oh well.

Sorry!