Powered by
/src$ make
  • Home
  • About
  • Directory
  • Contact
  • Home
  • About
  • Directory
  • Contact

C++ Object Oriented Programming, Inheritance, Virtual Functions Tutorial

1/27/2018

 
To see the youtube video where I explain this complicated topic in simple words, click here.

What is Object Oriented Programming?

"Object oriented programming" is a style of programming where things are modeled as objects that have certain features and attributes that describe them, and actions that they can perform. For example, animals have names and a certain amount of legs, and they're also able to make sounds. In our code, we would create an Animal class that has variables and methods to model this behavior. 

However, the trick that makes object oriented programming work well is by having hierarchies of classes to save on lines of code, while also remember to include all the features and methods that are necessary to describe the object. 

For example, if we wanted to make classes for Dogs, Cats, Squirrels, Horses, Zebras, Pandas, and Centipedes...they're all animals and have similar characteristics that we'd use to describe them, but it would be inconvenient to have to write the same lines of code for including those similar features in each individual class. Instead, we can create a base Animal class with the characteristics that all animals have, and we can create derived classes for each individual animal that will inherit from the base class, so that the derived classes also have the features and methods that the base class has. 

A Brief Warmup - (Base) Class Example

If you don't already know what classes are or how they work in C++, then look at the tutorial where we go over classes, templates, and custom data structures, as it explains how classes work very well.

​For now, we start with a simple base class, and test it out.
 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
// Copyright srcmake.com 2018.
#include <iostream>
using namespace std;

///////////////////////////////////////
// THE FISH BASE CLASS
class Fish
        {
        protected:
                string name;
                bool hasScales;
        public:
                void Swim();
        };

void Fish::Swim()
        {
        cout << "*uses fins to paddle forward*" << endl;
        }
///////////////////////////////////////


///////////////////////////////////////
// MAIN
int main()
        {
        Fish fishie;
        fishie.Swim();
        
        return 0;
        }
///////////////////////////////////////
As you can see, we have a fish class with two attributes, name and hasScales, and there's one public method available named Swim. We declare the name and hasScales variables as protected, meaning they're private, but derived classes can access them (as we'll see in the next section).

A Derived Class: It Inherits From The Base Class 

So Fish is our base class, but there are many kinds of fish: goldfish, salmon, tuna, sharks, whales, and even eels! A lot of aquatic animals fall under the category of "fish". 

We're going to create a class called Tuna that inherits from the Fish 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
// Copyright srcmake.com 2018.
#include <iostream>
using namespace std;

///////////////////////////////////////
// THE FISH BASE CLASS
class Fish
        {
        protected:
                string name;
                bool hasScales;
        public:
                void Swim();
        };

void Fish::Swim()
        {
        cout << "*uses fins to paddle forward*" << endl;
        }
///////////////////////////////////////


///////////////////////////////////////
// THE TUNA DERIVED CLASS
class Tuna: public Fish // <- if you don't include that public keyword, public methods won't get inherited.
        {
        private:
                bool saltwaterFish;
        public:
                Tuna();
                void Canned();
        };
        
Tuna::Tuna()
        {
        // We're able to access the protected variables from the Fish class
        // even though we didn't declare it in this class.
        name = "Tuna";
        hasScales = true;
        // We can also access our own private variables.
        saltwaterFish = true;
        }
        
void Tuna::Canned()
        {
        cout << "People like to put me in cans." << endl;
        }
        
///////////////////////////////////////


///////////////////////////////////////
// MAIN
int main()
        {
        Fish fishie;
        fishie.Swim();
        
        Tuna tuna;
        tuna.Canned();
        // The Tuna class inherited the Fish Swim method ONLY because we used 
        // the public keywordwhen we did "class Tuna: public Fish". You don't 
        // HAVE to use the public keyword, but if you do then the derived class 
        // inherits the base classes public variables and methods.
        tuna.Swim();
        
        return 0;
        }
///////////////////////////////////////
You can see the syntax for inheritance, just use a semicolon and the base classes name. The public keyword allows the derived class to use public methods from the base class. (Take away the public keyword in line 25, and the "tuna.Swim()" on line 65 will throw an error. 

The Virtual Keyword

So far, our derived class was really simple. But what happens if we want to override one of the methods in the base class? For example, our Fish class says that fish swim by "using fins to paddle forward", but Eels don't have fins...they swim by wiggling their body. How can we compensate for this?

The answer is the virtual keyword. The virtual keyword allows a derived class to override the base class's method definition with its own.

In our case, we're adding the virtual keyword to line 13 in our base Fish class for the Swim method, and we'll override that method in our Eel derived class. Here's the code:
 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
79
80
81
82
83
84
85
// Copyright srcmake.com 2018.
#include <iostream>
using namespace std;

///////////////////////////////////////
// THE FISH BASE CLASS
class Fish
        {
        protected:
                string name;
                bool hasScales;
        public:
                virtual void Swim();
        };

void Fish::Swim()
        {
        cout << "*uses fins to paddle forward*" << endl;
        }
///////////////////////////////////////


///////////////////////////////////////
// THE EEL DERIVED CLASS
class Eel: public Fish 
        {
        public:
                void Swim();
        };
        
void Eel::Swim()
        {
        cout << "*wiggles body to move forward*" << endl;
        }
        
///////////////////////////////////////


///////////////////////////////////////
// FUNCTION THAT ACCEPTS FISH
void PrintSwim(Fish somefish)
        {
        somefish.Swim();
        }
///////////////////////////////////////


///////////////////////////////////////
// MAIN
int main()
        {
        // Base class. 
        Fish fishie;
        fishie.Swim(); // "uses fins"
        
        // Derived class.
        Eel eel;
        // The following command will be "wiggles body" regardless of whether
        // line 13 uses the virtual keyword or not. Overriding is the default.
        eel.Swim(); // "wiggles body"
        
        /*
   The reason that the virtual keyword is used is because of situations
   where you pass objects into functions. 
   
   Without the virtual keyword on line 13, the following two lines would 
   say "uses fins" because Eel will get cast down to an Animal.
   
   One solution is to overload PrintSwim to also accept (Eel someeel)
   as a parameter, but that's very messy considering we want a bunch of
   aquatic animals. 
   
   Instead, we keep the function with the base class, and use the virtual keyword
   inside of the base class's method prototypes so that the overriding works.
   
   See https://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c
   */
        
        // Remove the virtual keyword from line 13 and see what happens.
        PrintSwim(fishie); // "uses fins"
        PrintSwim(eel); // With virtual: "wiggles body" | without virtual: "uses fins"
        
        return 0;
        }
///////////////////////////////////////
You can see that the Eel object named eel will use the Swim method with it's own definition ("wiggles body") when used normally. However, that would have happened even if the virtual keyword wasn't there.

The reason to use the virtual keyword is so that if you pass an object to a function, the function can accept the base class as the parameter, but use the derived class's overridden definition. 

​If this doesn't make sense, watch the video where I explain it.

Abstract Classes: Pure Virtual Functions

The final thing we need to know about is the concept of abstract classes. An abstract class is one with an incomplete method definition. For example, we might have all Fish eat, but different fish eat different things, and it doesn't make sense to create a default definition for an Eat method and overriding it: it makes better sense to let each individual fish derived class define an Eat method themselves.

So we'll create an Eat method in the Fish class, but we use a pure virtual function and we don't write an Eat definition. Basically, this means that all derived classes MUST define the Eat method themselves, or the compiler will throw an error.
 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
// Copyright srcmake.com 2018.
#include <iostream>
using namespace std;

///////////////////////////////////////
// THE FISH BASE CLASS
class Fish
        {
        public:
                virtual void Eat() = 0;
        };
///////////////////////////////////////


///////////////////////////////////////
// THE GOLDISH DERIVED CLASS
class GoldFish: public Fish 
        {
        public:
                void Eat();
        };
        
void GoldFish::Eat()
        {
        cout << "I eat fish flakes." << endl;
        }
///////////////////////////////////////


///////////////////////////////////////
// THE GOLDISH DERIVED CLASS
class Shark: public Fish 
        {
        public:
                void Eat();
        };
        
void Shark::Eat()
        {
        cout << "I hunt for blood!" << endl;
        }
///////////////////////////////////////


///////////////////////////////////////
// MAIN
int main()
        {
        GoldFish srcgoldie;
        srcgoldie.Eat();
        
        Shark srcshark;
        srcshark.Eat();
        
        return 0;
        }
///////////////////////////////////////
As you can see, a "pure" virtual function just has an "= 0" at the end of it's prototype in the class definition. It means that the GoldFish and Shark derived classes HAVE to have a definition for the "Eat" method.

Conclusion

With this knowledge (on top of using classes in the previous article), you're an expert at object oriented programming! Congrats. 

When modelling objects and larger projects, always keep in mind hierarchies of descriptions so that you can write as little code as possible. It seems pointless for small projects, but for very very large projects, planning the architecture, classes, and objects is more important than the coding itself.
To see the youtube video where I explain this complicated topic in simple words, watch this video:
Like this content and want more? Feel free to look around and find another blog post that interests you. You can also contact me through one of the various social media channels. 

Twitter: @srcmake
Discord: srcmake#3644
Youtube: srcmake
Twitch: www.twitch.tv/srcmake
​Github: srcmake
References
1. www.geeksforgeeks.org/pure-virtual-functions-and-abstract-classes/
2. en.wikibooks.org/wiki/C%2B%2B_Programming/Classes/Abstract_Classes
3. ​https://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c

Comments are closed.

    Author

    Hi, I'm srcmake. I play video games and develop software. 

    Pro-tip: Click the "DIRECTORY" button in the menu to find a list of blog posts.
    Metamask tip button
    License: All code and instructions are provided under the MIT License.

    Discord

    Chat with me.


    Youtube

    Watch my videos.


    Twitter

    Get the latest news.


    Twitch

    See the me code live.


    Github

    My latest projects.

Powered by Create your own unique website with customizable templates.