C++: Inheritance and Friends

Looking for in-depth C tutorials? Try SourceCrunch.

Inheritance is an important concept in C++ when working with classes, which essentially allows one class to inherit functionality from another.

The easiest way to express this concept is for me to show you an example. Firstly, let's create a basic class called "Fish". This is going to be a really generalized class which contains some basic, generic information about fish which we'd generally want in all objects that are of type "Fish". For the sake of simplicity, let's just structure and implement at the same time:

1
2
3
4
5
6
7
8
9
10
class Fish
{
public:
	Fish(){ speed = 0; } //Basic constructor
	void speed_up() { speed += 2; }
	void slow_down() { speed -= 2; }
	void output() const { cout << speed; }
protected:
	int speed;
};

We're going to refer to this class as the base class. We're going to do this, because the plan is that we're going to create a few classes for a few different types of fish - all of which we want to possess the basic properties and functions shown in our "Fish" class, but we also want them to have some unique functionality of their own. If we wanted to we could just copy/paste everything in our "Fish" class into any of these classes (Perhaps "Cod" and "Haddock"), however this repetition should be triggering your bad programming senses, and would also mean that if you wanted to make a small change to the base of all the fish classes, you'd have to modify the version of code present in each individual class.

To solve this issue, we can simply make some new classes and tell them to inherit from the "Fish" base class. This can do different things depending on the access modifier used to inherit from the base class, but for the most part it'll just give the "child" class (which inherits from the base) all the public and protected functionality from the base class - the private stuff will also be "inherited" so to speak, however will only be accessible by the the stuff in the base class. Just to re-iterate the protected section, which we glossed over before - its purpose is to provide a way to give access to data and functions to inherited classes and "friends" - so not open to everyone like public, and not closed to everyone (apart from "friends") like private.

As I alluded to earlier, when you inherit from a base class you must also specify an access modifier to inherit with. Inheriting with public is by far the most common, and is what you'll use most of the time -- essentially, public stuff stays public, private stuff stays private, and protected stuff stays protected. Inheriting with the private access modifier makes all public stuff private, and leaves the other private and protected stuff alone, and inheriting with protected makes all public stuff protected, and leaves all private stuff and other protected stuff alone.

With this in mind, we can make a class inherit from a base class by putting a colon after the class name, followed by the access modifier we're inheriting with, followed by the base class name. So we could make a "Cod" class that inherits from "Fish" with public access restriction like so:

1
2
3
4
5
class Cod : public Fish
{
public:
	Cod(){} //Basic constructor
};

As we inherited with the "public" access modifier, any "Cod" objects will have access to all the public member functions we made in "Fish" -- "speed_up", "slow_down", and "output". It's worth noting that the constructor(s) and destructor(s) aren't "copied across" in the process so to speak, however they are still called during the relevant processes. The "Fish" constructor is called in the construction process of a "Cod" object for example, as could be seen by putting a cout in the constructor and then creating a "Cod" object.

The whole point of all "Cod" objects not just being "Fish" is that there is something unique about "Cod" which makes them need to be classified differently. As such, we should probably give "Cod" objects some unique functionality. Since we declared the "speed" integer in a protected section, we can access "speed" with members functions inside the "Cod" class (we wouldn't be able to if it was private), and as such, perhaps the unique thing about "Cod"s is that they start with a speed of 10 -- we could specify this in our "Cod" constructor:

1
2
3
4
5
class Cod : public Fish
{
public:
	Cod(){ speed = 10; } //Basic constructor
};

You can also overload/"overwrite" some of the base class functions if you want to. So if we simply re-write a function with the same name and parameters in an inherited class, it will be used instead of the base class version - say for example that "Cod"s should actually speed up by 20 each time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

using namespace std;

class Fish
{
protected:
	int speed;
public:
	Fish() : speed(0) {}
	void speed_up() { speed += 10; }
	void slow_down() { speed -= 10; }
	void output() const { cout << speed << endl; }
};

class Cod : public Fish
{
public:
	Cod() { speed = 10; } //Cods start with a speed of 10
	void speed_up() { speed += 20; } //Overwrite base 'speed_up' member function
};

int main() //Let's test this out!
{
	Cod bob; //A new "Cod"
	bob.speed_up();
	bob.output();

	Fish freddie; //A new "Fish" (not a "Cod"!)
	freddie.speed_up();
	freddie.output();

	return 0;
}

From running the code above, you should see that "bob" brags a speed of 30 from speeding up once (since he started at 10 due to the constructor then added 20), whereas "freddie" (the 'regular' fish) only has a speed of 10 (he started at 0 and then added 10). Also note that the constructor initialization list method of setting member variables can also be used to call the constructor of the base class. This becomes more useful when base constructors are more complex , however in this example could be used to utilize the base constructor to set the speed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Fish
{
protected:
	int speed;
public:
	Fish() : speed(0) {}
	Fish(int s) : speed(s) {}
	void speed_up() { speed += 10; }
	void slow_down() { speed -= 10; }
	void output() const { cout << speed << endl; }
};

class Cod : public Fish
{
public:
	Cod() : Fish(10) {} //Cods start with a speed of 10
	void speed_up() { speed += 20; }
};

Obviously our "Fish" class isn't super practical, but it makes for a nice demonstration of the concept. We could also add custom variables and functions in different restrictive sections - so maybe "Cod"s should have a scale count whereas regular "Fish"es shouldn't. Try to add this functionality on your own as well as adding a "Haddock" class with some unique functionality if you're up to the task.

An even bigger and better task which you may wish to try and accomplish, is making a very simple text-based RPG (Role Playing Game), or at least some classes that might power such a system. You might want some classes for players, NPCs, enemies, weapons, and so on, and you should try to use inheritance to represent the "is a" relationships, so a gun is a weapon, and so will probably want to inherit (publicly) from the "weapon" class.

The "Weapon" class, for example, might have a basic "attack" member function which has a general formula for how much damage to do to the enemy. A nice way of actually doing this damage to the enemy (which, let's just assume is an object of the "Enemy" class) is for the "attack" member function to take an "Enemy" pointer. The -> operator in C++ with regards to pointers essentially represents actions on the object a pointer is pointing to, so a->b is equal to (*a).b, and as such this kind of functionality could be utilized in an "attack" member function. This functionality is often used in a variety of applications and so is something I recommend you try to get used to. An example of some classes I whipped up for my little RPG are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>

using namespace std;

class Enemy
{
public:
	Enemy(int h = 100) : health(h) {} //health = h;
	void take_damage(int damage)
	{
		health -= damage;
	}
	int get_health() { return health; }
private:
	int health;
};

class Weapon
{
public:
	Weapon(int dmg_r = 10) : damage_rating(dmg_r) {} //damage_rating = dmg_r;
	void attack(Enemy* e)
	{
		e->take_damage(3*damage_rating); //Default general damage formula
	}
protected:
	int damage_rating;
};

class Gun : public Weapon
{
public:
	Gun(int dmg_r = 5, int bps = 5) : Weapon(dmg_r), bullets_per_second(bps) {} //damage_rating = dmg_r; bullets_per_second = bps;
	void attack(Enemy* e)
	{
		e->take_damage(2*bullets_per_second*damage_rating); //Gun damage formula
	}
private:
	int bullets_per_second;
};

int main() //Let's play around with our classes
{
	char yn; //A char we will use for decision making

	cout << "Someone gives you a gun. \n\n";
	Gun gun_one; //Our character's only "Weapon", a "Gun"

	Enemy zombie;
	cout << "A zombie ambushes you! It has "<< zombie.get_health() << " health!" << endl;
	cout << "You only have one weapon, a gun. Shoot? (Y/N)" << endl;
	cin >> yn;

	if(yn == 'Y' || yn =='y')
	{
		gun_one.attack(&zombie); //Attack the zombie! (Pass by pointer)
		cout << "The zombie has "<< zombie.get_health() << " health remaining!" << endl;
	}

	//TODO: A whole bunch of crap, zombie attacking back, etc.

	return 0;
}

You should be able to see how the above could then be expanded upon with extra logic and classes and fancy things, to create a very basic proper RPG! To really show off the inheritance we should probably add some more classes for things like swords, and maybe magic attacks, but I'll leave those for you to do.

To finish off this tutorial, we're just going to talk a little bit about friend classes and friend functions. This essentially just gives some class(es) or some function(s) access to private (and protected), as well of course to the public sections of a class! This is done by using the friend keyword inside of the class who's private and protected sections you wish to share, and then writing the function prototype, or the class keyword followed by the class name. That's pretty much all there is to it.

So in the simple RPG snippet presented earlier, let's pretend we also added an "NPC" class which handles the functionality of non-playable characters (perhaps we have dialogue and other fancy things stored in some multi-dimensional arrays or something). Since we want NPCs to be able to modify weapon data (for enchantments or whatever), however we don't want NPCs to inherit from the "Weapon" class, we can make the "NPC" class a friend of the "Weapon" class by using the line friend class NPC; in the "Weapon" class. As "Gun" inherits from "Weapon", "Gun" will also treat "NPC" as a friend class (although the NPC's member functions may need to have a different version to work with "Gun" objects). To show this, the modified version of the "Weapon" class in our example as well as the new "NPC" class are below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Weapon
{
public:
	Weapon(int dmg_r = 10) { damage_rating = dmg_r; } //Just to mix things up a bit I've moved this away from the constructor initialization list
	void attack(Enemy* e)
	{
		e->take_damage(3*damage_rating); //Default general damage formula
	}
protected:
	int damage_rating;
	friend class NPC; //NPC is a friend class
};

class NPC
{
public:
	void enchant_weapon(Weapon* w)
	{
		w->damage_rating += 10;
	}
	void enchant_weapon(Gun* g)
	{
		g->damage_rating =+ 3;
	}
};

The above could then be utilized in the "main" function by creating a new NPC and just seeing the damage difference to the zombie from them enchanting the gun (or any other weapon).