3. Inheritance in C++
The third article in the series.
Sherman Chin, Wednesday 06 October 2004 - 10:14:13

Welcome back! In our last article, we learned how to apply the concept of class and object in OOP. Today, we will be shifting our focus to inheritance. As I promised before, we will see how to code our Fighter and Wizard classes, which are more specialized classes that can be inherited from our Character class that we have created previously.

What is inheritance? Inheritance is a "kind of" relationship. Think of this way: a wizard is a "kind of" character in our game and a fighter is also a "kind of" character in our game. Notice that the rule of classes being English "nouns" still apply as we have seen in our last tutorial. Character, Wizard and Fighter are all nouns and are our classes in our code.

Two new terms that is of interest when discussing inheritance are base class and derived class. The base class in our game is the "Character" class. Think of it as the parent class. The derived classes in our game are the "Wizard" class and the "Fighter" class. They are the child classes. Let us see the actual inheritance in our code:

#include <iostream.h>

class Character
{
private:
char name[25];
int level;
int hitPoints;
int experience;
public:
void talk(void)
{
cout << "Hello! I am a character.";
}
void walk(void)
{
// We have to write the code to make the 
// character walk here.
}
};

class Wizard : public Character
{
};

class Fighter: public Character
{
};

void main(void)
{
Character adam;
adam.talk();
}

The syntax for the derived classes is "class derivedclassname : accessspecifier baseclassname". Using the syntax, we indicate which base class is the particular derived class derived from. This is done by placing a colon after the name of the derived class, followed by a keyword such as "public" and then the base class name. The colon simply means "is derived from". Therefore, our Wizard and Fighter classes are derived from our Character class. The keyword "public" is our access specifier.

We have seen access specifiers being used in our Character class in our last tutorial. There, we saw that the public access specifier meant that the class member could be accessed outside the class whereas the private access specifier indicated that the class member could not be accessed outside the class. Now, we see that the access specifiers also apply to the class itself albeit in a slightly different way. I will explain more later on but for now, just key in the derived class syntax and journey onward.


Let us declare objects of our Wizard and Fighter classes. After that, we can call the derived classes' base class function which they inherited, in our case, talk().
#include


class Character
{
private:
char name[25];
int level;
int hitPoints;
int experience;
public:
void talk(void)
{
cout << "Hello! I am a character." << endl;
}
void walk(void)
{
// We have to write the code to make the 
// character walk here.
}
};

class Wizard : public Character
{
};

class Fighter: public Character
{
};

void main(void)
{
Character adam;
Wizard merlin;
Fighter connan;
adam.talk();
merlin.talk();
connan.talk();
}

In our program, I have added the "endl" keyword to the cout statement in the talk() function of the base class "Character". All this does is format the display so that we do a line feed and carriage return. In other words, we end the line (endl) and begin displaying on the next line so that the output is easier to see. It has nothing to do with our concept of inheritance. Precede the "endl" keyword with the "<<" operator. Here the "<<" operator acts as concatenation operator. We can easily type: cout << "Hello! I am a character." << "I am now talking!"; The output will be: Hello! I am character.I am now talking!". We have just concatenated(joined) the two strings together.

We have 2 new objects. The merlin object is of the class Wizard and the connan object is of the class Fighter. Although the bodies of the Wizard and Fighter classes are both empty we can call the talk function using our access operator (.) since they both inherited the function from their base class, Character. The output will be:

Hello! I am a character.
Hello! I am a character.
Hello! I am a character.


Let us digress to our access specifiers. Our Wizard (and our Fighter) class has a "public" access specifier. This gives its OBJECTS accessibility to the public members of the base class. The private members of the base class are not directly accessible by our derived class OBJECTS. It is legal to code:

class Wizard : public Character
.
.
.
merlin.talk();
as we have done in our actual program but it is illegal to code:

class Wizard : private Character
.
.
.
merlin.talk(); // Compiler will generate 
// ERROR when compiling!!!

The difference between the two segments of code is the access specifier. The first segment states that the Wizard class is publicly derived from the Character class so everything works based on the class member access specifiers in the Character class. However, in the second segment of code, the Wizard class is privately derived from the Character class so the private access specifier overwrites the class member access specifiers found in the base Character class. If a derived class is declared as having a private access specifier, its OBJECTS will not be able to access the both the private and the public members of the base class. The reason why I stress on the word "objects" is because you can still code:

class Wizard : private Character
{
public:
void talk(void)
{
Character::talk(); // This is legal. 
// There will be NO errors.
} 
};

Although the Wizard class is PRIVATELY derived from the Character class, we can still call the talk() function of the Character class because we are calling the function from within the Wizard class itself and NOT through a Wizard class OBJECT. Okay, some of you might be wondering why we have a "Character::" preceding the talk() function. This is because we have declared another talk() function within the Wizard class. The "Character::" allows us to differentiate which talk() function we are referring to. In this case, we are referring to the Character class' talk() function. The double colon (::) preceding the class name is known as the scope resolution operator. The scope resolution operator is used whenever you want to tell what class something belongs to when you are outside the class specification.

It is interesting to know that we can legally code:

class Wizard : private Character
{
public:
void talk(void)
{
talk(); // A call to this function again, 
// hence causing an infinite loop
} 
};

However, since we do not have the scope resolution operator, the C++ compiler will assume that we are calling our Wizard class talk() function again within our Wizard class talk() function itself. Thus, resulting in an infinite loop that will inevitably cause a runtime error. Please note that a compile time error is an error encountered when you are compiling your program. This type of error is usually syntax errors that will prevent the program from running at all. Compile time errors are spotted by your C++ compiler. On the other hand, runtime errors are errors that occur when your program is running. They are usually logic errors - errors that allow the program to run but not the way you expected it to run.


Now, on with our main program:

#include <iostream.h>

class Character
{
private:
char name[25];
int level;
int hitPoints;
int experience;
public:
void talk(void)
{
cout << "Hello! I am a character." << endl;
}
void walk(void)
{
// We have to write the code to make the 
// character walk here.
}
};

class Wizard : public Character
{
public:
void talk(void)
{
Character::talk();
cout << "I am a wizard as well." << endl;
}

void castSpell(void)
{
cout << "I can cast spells." << endl;
}
};

class Fighter: public Character
{
};

void main(void)
{
Character adam;
adam.talk();
Wizard merlin;
merlin.talk();
merlin.castSpell();
Fighter connan;
connan.talk();
}

Here, we have added code to our Wizard class. It now has its own talk() function that overwrites its base class Character talk() function. The output of the program will be as follows:

Hello! I am a character.
Hello! I am a character.
I am a wizard as well.
I can cast spells.
Hello! I am a character.

Let us make a little change to our program by deleting the Character::talk(); statement from our Wizard class talk() function. The output will be:

Hello! I am a character.
I am a wizard as well.
I can cast spells.
Hello! I am a character.

We have successfully overwritten our base class talk() function completely with our Wizard class so merlin only says: "I am a wizard as well. I can cast spells." He no longer says, "Hello! I am a character."

Of course as you have noticed, we have added a new castSpell() function to our Wizard class. When you type merlin.castSpell(), he will say, "I can cast spells."

Based on our observations, we can conclude that derived classes inherit the public members of our base class. Some people think of inheritance as a family tree. However, inheritance in OOP is slightly different from human families in certain aspects. Number one, a class usually inherits from a single parent and number two, derived classes tend to have more features than base classes, whereas human children often lack qualities possessed by their parents.

That ends today's tutorial. To cap things up, we have learned another important aspect of OOP, namely inheritance. Inheritance is a "kind of" relationship that allows us to make more specialized derived classes from generalized base class(es). The derived classes will inherit the public members of the base class. There is another kind of access specifier, "protected", that I have not mentioned about. The "protected" access specifier is usually utilized as a class member access specifier rather than a class access specifier. In this context, derived classes can also inherit the protected members of the base class. The advantage of protected members is that they can be accessed within base and derived class specifications but not outside of the class i.e. the "main" function.

More information on the protected access can always be found in any renowned C++ text books. Until next time, navigate knowledgeably in the realms of cyberspace!




this content item is from Sherman3D
( http://sherman3d.com/S3Dplugins/content/content.php?content.4 )