Class inheritance

You use inheritance when you want to create a new, more functional class of code, based on some existing class of code. Inheritance is a tricky topic to cover. Let's start with the concept of a derived class (or subclass).

Derived classes

The most natural way to consider inheritance is by analogy with the animal kingdom. The classification of living things is shown in the following screenshot:

Derived classes

What this diagram means is that Dog, Cat, Horse , and Human are all Mammals. What that means is that dog, cat, horse, and human all share some common characteristics, such as having common organs (brain with neocortex, lungs, liver, and uterus in females), while being completely different in other regard. How each walks is different. How each talks is also different.

What does that mean if you were coding creatures? You would only have to program the common functionality once. Then, you would implement the code for the different parts specifically for each of the dog, cat, horse and human classes.

A concrete example of the preceding figure is as follows:

#include <iostream>
using namespace std;
class Mammal
{
protected:
  // protected variables are like privates: they are
  // accessible in this class but not outside the class.
  // the difference between protected and private is
  // protected means accessible in derived subclasses also
int hp;
  double speed;

public:
  // Mammal constructor – runs FIRST before derived class ctors!
Mammal()
{
  hp = 100;
  speed = 1.0;
  cout << "A mammal is created!" << endl;
}
~Mammal()
{
  cout << "A mammal has fallen!" << endl;
}
// Common function to all Mammals and derivatives
  void breathe()
  {
    cout << "Breathe in.. breathe out" << endl;
  }
  virtual void talk()
  {
    cout << "Mammal talk.. override this function!" << endl;
  }
  // pure virtual function, (explained below)
  virtual void walk() = 0;
};

// This next line says "class Dog inherits from class Mammal"
class Dog : public Mammal // : is used for inheritance
{
public:
  Dog()
  {
cout << "A dog is born!" << endl;
}
~Dog()
{
  cout << "The dog died" << endl;
}
  virtual void talk() override
  {
    cout << "Woof!" << endl; // dogs only say woof!
  }
  // implements walking for a dog
  virtual void walk() override
  {
    cout << "Left front paw & back right paw, right front paw &  back left paw.. at the speed of " << speed << endl;
  }
};

class Cat : public Mammal
{
public:
  Cat()
  {
    cout << "A cat is born" << endl;
  }
  ~Cat()
  {
    cout << "The cat has died" << endl;
  }
virtual void talk() override
  {
    cout << "Meow!" << endl;
  }
// implements walking for a cat.. same as dog!
  virtual void walk() override
  {
    cout << "Left front paw & back right paw, right front paw &  back left paw.. at the speed of " << speed << endl;
  }
};

class Human : public Mammal
{
// Data member unique to Human (not found in other Mammals)
  bool civilized;
public:
  Human()
  {
    cout << "A new human is born" << endl;
    speed = 2.0; // change speed. Since derived class ctor
    // (ctor is short for constructor!) runs after base 
    // class ctor, initialization sticks initialize member 
    // variables specific to this class
    civilized = true;
  }
  ~Human()
  {
    cout << "The human has died" << endl;
  }
  virtual void talk() override
  {
    cout << "I'm good looking for a .. human" << endl;
  }
// implements walking for a human..
  virtual void walk() override
  {
    cout << "Left, right, left, right at the speed of " << speed  << endl;
  }
  // member function unique to human derivative
  void attack( Human & other )
  {
    // Human refuses to attack if civilized
    if( civilized )
      cout << "Why would a human attack another? Je refuse" <<  endl;
    else
      cout << "A human attacks another!" << endl;
  }
};

int main()
{
  Human human;
  human.breathe(); // breathe using Mammal base class  functionality
  human.talk();
  human.walk();

  Cat cat;
  cat.breathe(); // breathe using Mammal base class functionality
  cat.talk();
  cat.walk();

  Dog dog;
  dog.breathe();
  dog.talk();
  dog.walk();
}

All of Dog, Cat, and Human inherit from class Mammal. This means that dog, cat, and human are mammals, and many more.

Syntax of inheritance

The syntax of inheritance is quite simple. Let's take the Human class definition as an example. The following screenshot is a typical inheritance statement:

Syntax of inheritance

The class on the left of the colon (:) is the new, derived class, and the class on the right of the colon is the base class.

What does inheritance do?

The point of inheritance is for the derived class to take on all the characteristics (data members, member functions) of the base class, and then to extend it with even more functionality. For instance, all mammals have a breathe() function. By inheriting from the Mammal class, the Dog, Cat, and Human classes all automatically gain the ability to breathe().

Inheritance reduces replication of code since we don't have to re-implement common functionalities (such as .breathe()) for Dog, Cat, and Human. Instead, each of these derived classes enjoys the reuse of the breathe() function defined in class Mammal.

However, only the Human class has the attack()member function. This would mean that, in our code, only the Human class attacks. The cat.attack() function will introduce a compiler error, unless you write a member function attack() inside class Cat (or in class Mammal).

is-a relationship

Inheritance is often said to be an is-a relationship. When a Human class inherits from Mammal class, then we say that human is-a mammal.

is-a relationship

The Human inherits all the traits a Mammal has

For example, a Human object contains a Mammal function inside it, as follows:

class Human
{
  Mammal mammal;
};

In this example, we would say the human has-a Mammal on it somewhere (which would make sense if the human were pregnant, or somehow carrying a mammal).

is-a relationship

This Human class instance has some kind of mammal attached in it

Remember that we previously gave Player an Armor object inside it. It wouldn't make sense for the Player object to inherit from the Armor class, because it wouldn't make sense to say the Player is-an Armor. When deciding whether one class inherits from another or not in code design (for example, the Human class inherits from the Mammal class), you must always be able to comfortably say something like the Human class is-a Mammal. If the is-a statement sounds wrong, then it is likely that inheritance is the wrong relationship for that pair of objects.

In the preceding example, we're introducing a few new C++ keywords here. The first is protected.

protected variables

A protected member variable is different from a public or private variable. All three classes of variables are accessible inside the class in which they are defined. The difference between them is in regard to accessibility outside the class. A public variable is accessible anywhere inside the class and outside the class. A private variable is accessible inside the class but not outside the class. A protected variable is accessible inside the class, and inside of derived subclasses, but is not accessible outside the class. So, the hp and speed members of class Mammal will be accessible in the derived classes Dog, Cat, Horse, and Human, but not outside of these classes (in main() for instance).

Virtual functions

A virtual function is a member function whose implementation can be overridden in a derived class. In this example, the talk() member function (defined in class Mammal) is marked virtual. This means that the derived classes might or might not choose to implement their own version of what the talk() member function means.

Purely virtual functions (and abstract classes)

A purely virtual function is one whose implementation you are required to override in the derived class. The walk() function in class Mammal is purely virtual; it was declared like this:

virtual void walk() = 0;

The = 0 part at the end of the preceding code is what makes the function purely virtual.

The walk() function in class Mammal is purely virtual and this makes the Mammal class abstract. An abstract class in C++ is any class that has at least one purely virtual function.

If a class contains a purely virtual function and is abstract, then that class cannot be instantiated directly. That is, you cannot create a Mammal object now, on account of the purely virtual function walk(). If you tried to do the following code, you would get an error:

int main()
{
  Mammal mammal;
}

If you try to create a Mammal object, you will get the following error:

error C2259: 'Mammal' : cannot instantiate abstract class

You can, however, create instances of derivatives of class Mammal, as long as the derived classes have all of the purely virtual member functions implemented.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.77.153