Inheritance

The concept

Inheritance is a very powerful concept. It allows classes to inherit the members of other classes. When there are classes that have attributes in common, we can make them inherit from a base class, which contain those attributes, instead of redefining those attributes inside all of them.

Let us say we are creating a library which handle the events, creation and display of graphical user interfaces (GUI). We could create a class named Widget which contains member variables holding the position and size of a widget (A widget is an element inside a graphical user interface, for example, buttons, text boxes, windows, combo boxes, scroll bars...) and methods to manipulate those members. We could then make all the classes of the library that represent widgets inherit from the class Widget. By doing that, we could then, for example, code a class named Layout, that contains an array of pointers to objects of type Widget, which job would be to change the layout of the pointed widgets in function of the dimensions of the main window. Since that class would work on pointers of type Widget and that all widgets would inherit from the class Widget, it could handle any widget of any kind. The object Layout could only access the members the widgets inherit from the class Widget, but it would not be a problem since all that class needs to access from the widgets is their positions and dimensions.

An other example would be a class representing a weapon for a video game. All weapons have common attributes, for example, the damage they deal, the kind of damage they deal, the skills and level required to equip them... They however have specific attributes depending on their type. For example, the class Sword may inherit from SharpWeapon, possessing a member representing its sharpness, which in turn inherit from Weapon. The class Mace could inherit from BluntWeapon, possessing a member representing its weight, which inherit from Weapon.

Note that a class from which an other class inherit is called a parent class and a class which inherits from another class is called a child class of the class it inherits from. From the example above, the class Weapon is a parent of SharpWeapon and Mace is a child of BluntWeapon.

Making a class inherit from an other class

To make a class inherit from an other class, we simply have to add, in its definition, after its name, a colon followed by the keyword public and then the name of the class it inherits from.

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
#include <iostream> class Parent{ public: Parent() : _parentMember(4) { } void parentMethod() const { std::cout << _parentMember << std::endl; } private: int _parentMember; }; class Child : public Parent { public: Child() { } }; int main() { Child child; // The child class contains the members of its parent class. child.parentMethod(); return 0; }

To make a class inherit from many classes, we simply add, separated by commas, the keyword public followed by the name of the class, for each class.

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
#include <iostream> class Parent{ public: Parent() : _parentMember(4) { } void parentMethod() const { std::cout << _parentMember << std::endl; } private: int _parentMember; }; class SecondParent{ public: SecondParent() : _secondParentMember(31) { } void secondParentMethod() const { std::cout << _secondParentMember << std::endl; } private: int _secondParentMember; }; class Child : public Parent, public SecondParent { public: Child() { } }; int main() { Child child; // The child class contains the members of its parent classes. child.parentMethod(); child.secondParentMethod(); return 0; }

Private vs protected members

As we saw earlier, private members can only be accessed within the class it belongs to. Protected members are similar to private members, but they can also be accessed within the child classes of the class it belongs to.

Let us have a look at the following, faulty, code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A { public: A() : _a(0) {} private: int _a; }; class B : public A { public: B() { _a = 824; // Error: The member '_a' of the class 'A' is private. } };

If the member _a of the class A was defined as protected instead of private, the class B, which inherits from A, could access it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A { public: A() : _a(0) {} protected: int _a; }; class B : public A { public: B() { /* Now that the inherited member '_a' is protected instead of private, we can access it. */ _a = 824; } };

This is the same for methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A { public: protected: void protectedMethod() {} private: void privateMethod() {} }; class B : public A { public: B() { // It works: The method 'protectedMethod' is protected, not private. protectedMethod(); // Error: The method 'privateMethod' is private. privateMethod(); } };

Member name collision

Normally, from the child class, we can directly access, when they are not private, the members inherited from its parents:

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
#include <iostream> class Parent{ public: Parent() : _parentMember(4) { } protected: int _parentMember; }; class Child : public Parent { public: Child() { _parentMember = 53; } void printInheritedMember() const { std::cout << _parentMember << std::endl; } }; int main() { Child child; child.printInheritedMember(); return 0; }

What happens if a class inherit from a member which has the same name as one of its members? That would not cause any error, however, that inherited member would have to be accessed using the namespace of the class it belongs to:

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
#include <iostream> class A{ public: A() : _m(21) { } protected: int _m; }; class B : public A { public: B() : _m(78) { } void printMembers() const { // Prints the member '_m' of the current class. std::cout << _m << std::endl; // Also prints the member '_m' of the current class. std::cout << B::_m << std::endl; // Prints the member '_m' inherited from the class 'A'. std::cout << A::_m << std::endl; } private: int _m; }; int main() { B b; b.printMembers(); return 0; }

Here is an other example:

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
#include <iostream> class A{ public: void method() { std::cout << "Method of the class 'A'.\n"; } }; class B : public A { public: void method() { std::cout << "Method of the class 'B'.\n"; } }; int main() { B b; // Calls the method 'method' of the class 'B'. b.method(); // Also calls the method 'method' of the class 'B'. b.B::method(); // Calls the method 'method' of the class 'A'. b.A::method(); return 0; }

Again, an other example:

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
#include <iostream> class A{ protected: float _m; }; class B{ protected: unsigned _m; }; class C : public A, public B { public: C() { _m = -34; A::_m = 27.93; B::_m = 132; std::cout << C::_m << std::endl; std::cout << A::_m << std::endl; std::cout << B::_m << std::endl; } private: int _m; }; int main() { C c; return 0; }

Classes inheriting indirectly from the same class many times

If a class inherits from many classes which inherit from the same class, then it inherits of many instances of the members of that class that its parents inherit from. Each instance of the members of the class inherited in common by its parent is accessed using the namespace of the parent it is inherited through.

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
#include <iostream> class A{ protected: int _a; }; class B : public A{ protected: int _b; }; class C : public A{ protected: int _c; }; class D : public B, public C { public: D() { // Member '_a' inherited through 'B'. B::_a = 11; // Member '_a' inherited through 'C'. C::_a = 98; std::cout << B::_a << std::endl; std::cout << C::_a << std::endl; } private: int _d; }; int main() { D d; return 0; }

In the code above, the classes B and C are direct parents of D. The class A is an indirect parent of D. The class D inherit from A through B, but it also inherit from A through C. The result is that it inherits from the members of A twice. The class A therefore have two members which definition is int _a. The members of A inherited through B can be accessed using its namespace, B::, and the ones inherited from C using the namespace C::.

If the class A also had methods, then the class D would also had inherited from two instances of those methods. What would have been the difference between those two sets of methods? The methods inherited through B would be using the members of A inherited through B and the methods inherited through C would be using the members of A inherited through it.

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
#include <iostream> class A{ public: void setA(int a) { _a = a; } void printA() const { std::cout << _a << std::endl; } protected: int _a; }; class B : public A{ protected: int _b; }; class C : public A{ protected: int _c; }; class D : public B, public C { public: D() { B::setA(14); C::setA(70); B::printA(); C::printA(); } private: int _d; }; int main() { D d; return 0; }

The constructor of parent classes

The constructor of a child class calls the constructors or its parent classes, before calling the constructors of its member objects. We can give arguments to the constructors of the parent classes the same way we give parameters to the constructors of member objects, except that we write the name of the class instead of the name of the object.

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
#include <iostream> class A{ public: A(int a) : _a(a) { std::cout << "Value of '_a': " << _a << ".\n"; } private: int _a; }; class B : public A { public: B(int b) : A(b*b), _b(b) { std::cout << "Value of '_b': " << _b << ".\n"; } private: int _b; }; int main() { B b(6); return 0; }

Here is an example to show the constructor calling order:

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
#include <iostream> class A{ public: A() { std::cout << "Constructor of class A.\n"; } }; class B{ public: B() { std::cout << "Constructor of class B.\n"; } }; class C : public A { public: C() { std::cout << "Constructor of class C.\n"; } private: B _a; }; int main() { C c; return 0; }

The destructor of parent classes

The destructor of a child class calls the destructors of its parent classes, after calling the destructors of its member objects.

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
#include <iostream> class A{ public: ~A() { std::cout << "Destructor of class A.\n"; } }; class B{ public: ~B() { std::cout << "Destructor of class B.\n"; } }; class C : public A { public: ~C() { std::cout << "Destructor of class C.\n"; } private: B _a; }; int main() { C c; return 0; }

Pointers of parent class type

Any pointer of parent class type can point to any object of its, direct and indirect, children classes. It can, however, only access the members the pointed object inherits through its class.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream> class Weapon { public: void setDamage(int damage) { _damage = damage; } int getDamage() const { return _damage; } protected: int _damage; }; class SharpWeapon : public Weapon { public: void setSharpness(float sharpness) { _sharpness = sharpness; } float getSharpness() const { return _sharpness; } protected: float _sharpness; // From 0 to 10. }; class Sword : public SharpWeapon { public: void setDoubleEdged(bool doubleEdged) { _doubleEdged = doubleEdged; } bool isDoubleEdged() const { return _doubleEdged; } protected: bool _doubleEdged; }; int main() { Sword sword; // The class 'Sword' inherits from 'Weapon'. Weapon *weapon = &sword; /* Accesses the method 'setDamage' of the object 'Sword', inherited from the class 'Weapon'. */ weapon->setDamage(50); // Error: The method 'setSharpness' has been inherited through the class 'Weapon'. weapon->setSharpness(0.32); // The class 'Sword' inherits from 'SharpWeapon'. SharpWeapon * sharpWeapon = &sword; /* Accesses the method 'setSharpness' of the object 'Sword', inherited from the class 'SharpWeapon'. */ sharpWeapon->setSharpness(7.7); // Error: The method 'setDoubleEdged' has been inherited through the class 'SharpWeapon'. sharpWeapon->setDoubleEdged(true); return 0; }

Here is a main function without any error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main() { Sword sword; Weapon *weapon = &sword; SharpWeapon * sharpWeapon = &sword; Sword *ptrSword = &sword; weapon->setDamage(83); sharpWeapon->setSharpness(6.8); ptrSword->setDoubleEdged(false); std::cout << "Damage: " << sword.getDamage() << ".\n"; std::cout << "Sharpness: " << sword.getSharpness() << ".\n"; std::cout << "Double-edged: " << (sword.isDoubleEdged()?"true":"false") << ".\n"; return 0; }

Choosing the parent classes

A square is a rectangle, but a rectangle is not a square. A square is a special kind of rectangle. If we defined a class named Square to represent a square and a class Rectangle to represent a rectangle, we could think it is a good idea to make Square inherit from Rectangle. However, even though it logically makes sense, in a programming point of view, it is not ideal, because the class Rectangle would require 2 members to represent its dimensions and Square only 1. Making Square inherit from Rectangle would make it inherit those 2 members, even though it requires only one. A better alternative would be to create a class named Shape and make both Square and Rectangle inherit from it.