C++ OOPs: Polymorphism

 
  • Polymorphism: meaning having Many Forms
  • Polymorphism is about an object's ability to provide different meaning or usage to Methods or Operators in different Contexts when they are called on Object.

Function/Operator Overloading:

  • Polymorphism represents possibility to have multiple implementations of the same functions.
  • Simple example of Polymorphism in C++ is Overloading.
  • A function with the Same Name can have different behavior according to the context of its call i.e. with different function signatures i.e. with different number / type / sequence of parameters or different return types.

Function Overriding:

  • When Same Function/Operator is defined in different classes, which Function/Operator gets called at Run-time will depend on which class’s object is actually being referenced.

Polymorphism & Inheritance:

  • The most interesting concepts of Polymorphism are related to Inheritance.
  • :heavy_check_mark: A pointer of Base class can be used as pointer of Derived class, i.e. Base class pointer can contain the pointer of it's Derived Class. It’s valid.
    • We can use pointer of a Base class as a pointer of the Derived class:
    • Such assignment of Derived class object to Base class pointer has following Problems:
      • When we try to call a Member Function of Derived class which is not available with Base class. This is because Base class is not aware of Derived class all functions. This results in compilation error.
      • When we try to call a Member Function of Base class, it can be Overridden in Derived class.
        • Base class pointer will only call Base class member function, even if it is overridden in derived class, if polymorphism is not used by declaring member function in base class to be virtual.
  • :x: But a pointer of Derived class cannot contain object of Base class. You will get an error like: Cannot convert from base to derived class

NoPolymorphism_NoVirtualFunction.cpp

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
#include <iostream>
using namespace std;

class baseClass
{
public:
  baseClass(int val) :someValue(val) {	}

  void info()	{
    cout << "Info member function of base class" << endl;
  }
protected:
  int someValue;
};

class derivedClass1 : public baseClass
{
public:
  derivedClass1(int val) :baseClass(val) {	}

  void info() {
    cout << "Info member function of derived class 1" << endl;
  }
};

class derivedClass2 : public baseClass
{
public:
  derivedClass2(int val) :baseClass(val) {	}

  void info()	{
    cout << "Info member function of derived class 2" << endl;
  }
};

int main()
{
  derivedClass1	child1(1);
  derivedClass2	child2(2);
  baseClass   parent(10);

  //pointers to base class
  baseClass*    basePtr1;
  baseClass*    basePtr2;
  baseClass*    basePtr3;

  //make pointers to base class point to objects of derived classes
  basePtr1 = &child1;
  basePtr2 = &child2;
  basePtr3 = &parent;
	
//  derivedClass1*  derivedPtr1;
//  derivedPtr1 = &parent;        // error C2440: '=' : cannot convert from 'baseClass *' to 'derivedClass1 *'
                                  // Cast from base to derived requires dynamic_cast or static_cast

  //calling info function
  // No Polymorphism happens here, both base class pointers call base class info() implementation.
  // Reason is there is no virtual function.
  basePtr1->info();
  basePtr2->info();

  basePtr3->info();

  getchar();
}

/*
  Output: No Polymorphism
  administrator@PTL011669:Polymorphism$ ./NoPolymorphism_NoVirtualFunction 
  Info member function of base class
  Info member function of base class
  Info member function of base class
  administrator@PTL011669:Polymorphism$ 

/*

NoPolymorphism_StaticDynamicCasting.cpp

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
86
87
88
89
90
91
92
#include <iostream>
using namespace std;

class baseClass
{
public:
  baseClass(int val) :someValue(val) {	}
  
  void info() {
    cout << "Info member function of base class" << endl;
  }
protected:
  int someValue;
};

class derivedClass1 : public baseClass
{
public:
  derivedClass1(int val) :baseClass(val) {	}

  void info() {
    cout << "Info member function of derived class 1" << endl;
  }
};

class derivedClass2 : public baseClass
{
public:
  derivedClass2(int val) :baseClass(val) {	}

  void info() {
    cout << "Info member function of derived class 2" << endl;
  }
};

int main()
{
  derivedClass1 child1(1);
  derivedClass2 child2(2);
  baseClass   parent(10);

  //pointers to base class
  baseClass*    basePtr1;
  baseClass*    basePtr2;
  baseClass*    basePtr3;
  derivedClass1*  derivedPtr1;

  //make pointers to base class point to objects of derived classes
  basePtr1 = &child1;
  basePtr2 = &child2;
  basePtr3 = &parent;
  // or below is also exactly ok, `dynamic_cast` is just adding `Run-time checks (RTTI)` before type casting as against above direct assignment.
  basePtr1 = dynamic_cast<baseClass*> (&child1);
  basePtr2 = dynamic_cast<baseClass*> (&child2);

  //calling info function
  basePtr1->info();
  basePtr2->info();

  // if `dynamic_cast` works, then `static_cast` is definitely gonna work.
  basePtr1 = static_cast<baseClass*> (&child1);
  basePtr2 = static_cast<baseClass*> (&child2);

//	derivedPtr1 = &parent;	  // error C2440: '=' : cannot convert from 'baseClass *' to 'derivedClass1 *'
							                // Cast from base to derived requires `dynamic_cast` or `static_cast`

  //calling info function
  basePtr1->info();
  basePtr2->info();

  // use static cast and call `info()` from derived class 1
  // here we are converting `basePtr1` (which contains child1 i.e. derived class object) to again derived class pointer.
  static_cast<derivedClass1*> (basePtr1)->info();

  // here, we are casting `basePtr3` (which contains parent i.e. base class object) to derived class pointer.
  // the result proves that content can be anything, the resultant casting will be in derived class and it's function will be called.
  static_cast<derivedClass2*> (basePtr3)->info();

  getchar();
}

/*
  Output: No Polymorphism
  administrator@PTL011669:Polymorphism$ ./NoPolymorphism_StaticDynamicCasting 
  Info member function of base class
  Info member function of base class
  Info member function of base class
  Info member function of base class
  Info member function of derived class 1
  Info member function of derived class 2
  administrator@PTL011669:Polymorphism$
*/

Virtual Function:

  • Virtual functions are functions those are expected to be overridden in the derived class.
  • By declaring Base class function as virtual, we can call functions of a Derived class using pointer of the Base class.
  • Declaring Base class function virtual is important, virtual keyword is not mandatory in Derived class.
  • But if Derived class function is declared virtual, it will pass on Polymorphism to it’s own derived class.
  • See below code:
    • As we have defined info() function in Base class as virtual, compiler first looks for info() member function in the appropriate Derived class.
    • If it cannot find member function in the Derived class, it will call member function of the Base class.

Polymorphism_VirtualFunction.cpp

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
using namespace std;

class baseClass
{
public:
  baseClass(int val) :someValue(val) {	}

  virtual void info() {
    cout << "Info member function of base class" << endl;
  }
protected:
  int someValue;
};

class derivedClass1 : public baseClass
{
public:
  derivedClass1(int val) :baseClass(val) {	}

  // virtual keyword here, is important w.r.t. derived class of derivedClass1
  virtual void info() {
    cout << "Info member function of derived class 1" << endl;
  }
};

class derivedClass2 : public baseClass
{
public:
  derivedClass2(int val) :baseClass(val) {	}

  // defining virtual function has effect on it's derived classes,
  // in terms that base class pointer can call appropriate derived class function
  void info() {
    cout << "Info member function of derived class 2" << endl;
  }
};

class derivedDerivedClass1 : public derivedClass1
{
public:
  derivedDerivedClass1(int val) :derivedClass1(val) {	}

  void info() {
    cout << "Info member function of derived derived class 1" << endl;
  }
};

int main()
{
  derivedClass1 child1(1);
  derivedClass2 child2(2);
  derivedDerivedClass1  childChild(3);
  baseClass   parent(10);

  //pointers to base class
  baseClass*    basePtr1;
  baseClass*    basePtr2;
  baseClass*    basePtr3;
  baseClass*    basePtr4;
  derivedClass1*  derivedPtr1;
  derivedClass1*  derivedPtr2;

  //make pointers to base class point to objects of derived classes
  basePtr1 = &child1;
  basePtr2 = &child2;
  basePtr3 = &parent;
  basePtr4 = &childChild;
  derivedPtr1 = &child1;
  derivedPtr2 = &childChild;

//  derivedPtr1 = &parent;    // error C2440: '=' : cannot convert from 'baseClass *' to 'derivedClass1 *'
                              // Cast from base to derived requires dynamic_cast or static_cast

  //calling info function
  // Polymorphism into effect as we have virtual info() function in base class
  basePtr1->info();
  basePtr2->info();
  basePtr4->info();           // obj of derived class's derived class (grandChild)
  derivedPtr2->info();        // obj of derived class's derived class (child)

  // normal pointers containing objects of same class
  basePtr3->info();
  derivedPtr1->info();

  getchar();
}

/*
  Output: Polymorphism
  administrator@PTL011669:Polymorphism$ ./Polymorphism_VirtualFunction 
  Info member function of derived class 1
  Info member function of derived class 2
  Info member function of derived derived class 1
  Info member function of derived derived class 1
  Info member function of base class
  Info member function of derived class 1
  administrator@PTL011669:Polymorphism$ 
*/

Late Binding (Run-time Polymorphism)

  • Also known as Dynamic or Run-time Binding.
  • Late Binding happens when virtual keyword is used in member function declaration. Example:
      printObjInfo(derivedClass *derivedPtr)
      {
          baseClass *basePtr = derivedPtr;
          basePtr->info();
      }
    
  • This will cause Late Binding as:
    1. info() is declared as virtual in baseClass.
    2. info() is overridden in both derivedClass1 & derivedClass2.
    3. basePtr will call respective derivedClass implementation of info(), based on which derivedClass’s object it receives as input in printObjInfo().
    4. Compiler cannot know at compile time about which derivedClass object will be passed to printObjInfo().
    5. So compiler will use Late Binding and binding will happen at run-time.
  • Late Binding Mechanism:
    • C++ implementation of virtual Function uses Late Binding which uses Virtual Table(VTable).
    • When a class declares a virtual function, most of the compilers add a hidden member variable that represents a pointer to Virtual Method Table(VMT/VTable).
    • We can call it as vptr.
    • This table represents an array of pointers to virtual functions.
    • At compile time, there is no information about which function will be called.
    • At run-time, pointers from VTable will point to right virtual functions. Virtual Method Table

Virtual Destructor

  • When you have a hierarchy of class, it is strongly recommended to have virtual destructor.
  • Virtual Destructor is needed, when we try to delete a Derived Class Object with a Base Class Pointer, otherwise Derived class destructor will never be called.
    • like:
      BaseClass *basePtr = new DerivedClass;
      delete basePtr;
      
  • See example for better understanding of need of virtual destructor:

NoVirtualDestructorProblem.cpp

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include<iostream>
using namespace std;

class BaseClass
{
public:
  BaseClass() {
    cout << "BaseClass Constructor..." << endl;
  }

  // No Virtual Destructor
  ~BaseClass() {
    cout << "BaseClass Destructor..." << endl;
  }
};

class DerivedClass: public BaseClass
{
public:
  DerivedClass() {
    cout << "DerivedClass Constructor..." << endl;
  }

  ~DerivedClass() {
    cout << "DerivedClass Destructor..." << endl;
  }
};

int main()
{
  {
    BaseClass	*basePtr, baseObj;
    basePtr = &baseObj;
    getchar();
  }
  cout << "-- All Ok BaseClass Constructor & Destructor called properly --\n";
	
  {
    DerivedClass *derivedPtr, derivedObj;
    derivedPtr  = &derivedObj;
    getchar();
  }
  cout << "-- All Ok Base, Derived class Constructor & Derived, Base Destructor called properly --\n";

  {
    BaseClass *basePtr;
    DerivedClass	derivedObj;
    basePtr	= &derivedObj;
    getchar();
  }
  cout << "-- All Ok Base, Derived class constructor & Derived, Base Destructor called properly --\n";
	
/*
  {
    DerivedClass	*derivedPtr;
    BaseClass		baseObj;
    derivedPtr = &baseObj;    // error C2440: '=' : cannot convert from 'baseClass *' to 'derivedClass1 *'
                              // Cast from base to derived requires dynamic_cast or static_cast
    getchar();
  }
  cout << "-----------------------------\n";
*/

  DerivedClass	derivedObj;
  {
    BaseClass *basePtr = &derivedObj;
    getchar();
//  delete basePtr;   // Runtime Error: Debug Assertion Failed
                      // as basePtr value derivedObj is not allocated using 'new' on Heap rather it's on Stack, so cannot use 'delete'
  }
  cout << "-- All Ok, Base, Derived class Constructor called & Derived, Base Destructor will be called at last properly --\n";

  {
    BaseClass	*basePtr = new DerivedClass;
    delete basePtr;
  }
  cout << "-- Here's the problem, Base, Derived class Constructor is called properly,\n\
   but only Base class Destructor gets called & Derived class Destructor never got called --\n";

  getchar();
}

/*
  Output:
  administrator@PTL011669:2_Virtual_Destructor$ ./NoVirtualDestructorProblem 
  BaseClass Constructor...

  BaseClass Destructor...
  -- All Ok BaseClass Constructor & Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  DerivedClass Destructor...
  BaseClass Destructor...
  -- All Ok Base, Derived class Constructor & Derived, Base Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  DerivedClass Destructor...
  BaseClass Destructor...
  -- All Ok Base, Derived class constructor & Derived, Base Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  -- All Ok, Base, Derived class Constructor called & Derived, Base Destructor will be called at last properly --
  BaseClass Constructor...
  DerivedClass Constructor...
  BaseClass Destructor...
  -- Here's the problem, Base, Derived class Constructor is called properly,
     but only Base class Destructor gets called & Derived class Destructor never got called --

  DerivedClass Destructor...
  BaseClass Destructor...
  administrator@PTL011669:2_Virtual_Destructor$
*/

VirtualDestructor.cpp

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include<iostream>
using namespace std;

class BaseClass
{
public:
  BaseClass() {
    cout << "BaseClass Constructor..." << endl;
  }

  // virtual Destructor
  virtual ~BaseClass() {
    cout << "BaseClass Destructor..." << endl;
  }
};

class DerivedClass: public BaseClass
{
public:
  DerivedClass() {
    cout << "DerivedClass Constructor..." << endl;
  }

  ~DerivedClass() {
    cout << "DerivedClass Destructor..." << endl;
  }
};

int main()
{
  {
    BaseClass *basePtr, baseObj;
    basePtr = &baseObj;
    getchar();
  }
  cout << "-- All Ok BaseClass Constructor & Destructor called properly --\n";

  {
    DerivedClass  *derivedPtr, derivedObj;
    derivedPtr  = &derivedObj;
    getchar();
  }
  cout << "-- All Ok Base, Derived class Constructor & Derived, Base Destructor called properly --\n";

  {
    BaseClass *basePtr;
    DerivedClass  derivedObj;
    basePtr	= &derivedObj;
    getchar();
  }
  cout << "-- All Ok Base, Derived class constructor & Derived, Base Destructor called properly --\n";

/*
  {
    DerivedClass  *derivedPtr;
    BaseClass baseObj;
    derivedPtr = &baseObj;  // error C2440: '=' : cannot convert from 'baseClass *' to 'derivedClass1 *'
                            // Cast from base to derived requires dynamic_cast or static_cast
    getchar();
  }
  cout << "-----------------------------\n";
*/

  DerivedClass  derivedObj;
  {
    BaseClass *basePtr = &derivedObj;
    getchar();
//  delete  basePtr;  // Runtime Error: Debug Assertion Failed
                      // as basePtr value derivedObj is not allocated using 'new' on Heap rather it's on Stack, so cacnot use 'delete'
  }
  cout << "-- All Ok, Base, Derived class Constructor called & Derived, Base Destructor will be called at last properly --\n";

  {
    BaseClass *basePtr = new DerivedClass;
    delete basePtr;
  }
  cout << "-- Here was the problem, Base, Derived class Constructor was called properly,\n\
  but only Base class Destructor was called in NoVirtualDestructorProblem example & Derived class Destructor never got called\n\
  This problem is solved here by Declaring BaseClass Destructor as 'virtual' --\n";
  getchar();
}

/*
  Output:
  administrator@PTL011669:2_Virtual_Destructor$ ./VirtualDestructor 
  BaseClass Constructor...

  BaseClass Destructor...
  -- All Ok BaseClass Constructor & Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  DerivedClass Destructor...
  BaseClass Destructor...
  -- All Ok Base, Derived class Constructor & Derived, Base Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  DerivedClass Destructor...
  BaseClass Destructor...
  -- All Ok Base, Derived class constructor & Derived, Base Destructor called properly --
  BaseClass Constructor...
  DerivedClass Constructor...

  -- All Ok, Base, Derived class Constructor called & Derived, Base Destructor will be called at last properly --
  BaseClass Constructor...
  DerivedClass Constructor...
  DerivedClass Destructor...
  BaseClass Destructor...
  -- Here was the problem, Base, Derived class Constructor was called properly,
     but only Base class Destructor was called in NoVirtualDestructorProblem example & Derived class Destructor never got called
     This problem is solved here by Declaring BaseClass Destructor as 'virtual' --

  DerivedClass Destructor...
  BaseClass Destructor...
  administrator@PTL011669:2_Virtual_Destructor$
*/

Abstract Class & Pure Virtual Function

  • An Abstract class is the one which has at least one Pure Virtual Function.
  • Pure Virtual Function: virtual void info() = 0;
  • When we use Pure Virtual function, then we must override it in Derived Class.
  • We cannot create an object of Abstract Class.
  • But we can use Pointer of Base class to point object of Derived Class.
  • When a function is declared pure virtual, it simply means that this function cannot get called dynamically, through a virtual dispatch mechanism.
  • Yet, this very same function can easily be called statically, non-virtually, directly (without virtual dispatch).
  • Pure Virtual unction can be callled Statically with Scope Specifier, as: baseAbstractClass::printClassName();
  • Recommendation:
    • Do not implement Pure Virtual Function in Declaration itself,
    • We can define it outside class definition, as in case of virtual ~baseAbstractClass()
    • Pure Virtual Function body should be outside class definition is the Standard, but VC++ allows it somehow.

    Pure Virtual Destructor in Abstract Class

    • C++ provides possibility to create Pure Virtual Destructor.
    • Pure Virtual Destructor also make class an Abstract class.
    • Difference between any Pure Virtual Function and Pure Virtual Destructor is that, Abstract class must have to implement Pure Virtual Destructor.
    • Normally Abstract class does not implement Pure Virtual Functions, rather it’s Derived classes must implement it.
    • We have to implement each and every Pure Virtual Function of Abstract Class in it's Derived Classes to make their objects, with an exception of Pure Virtual Destructor of Abstract Class.

      Use case for Pure Virtual Destructor

      • If you create a class with default implementations for its virtual methods and want to make it abstract, without forcing anyone to override any specific method, you can make the destructor pure virtual.
      • I don’t see much point in it but it’s possible.
      • Pure Virtual Destructor must be implemented, otherwise we get linking error.
      • Note that since the compiler will generate an implicit destructor for derived classes, if the class’s author does not do so, any derived classes will not be abstract. Therefore having the pure virtual destructor in the base class will not make any difference for the derived classes. It will only make the base class abstract.

    Pure Virtual Function with function body

    • Yes, Pure Virtual Function can have a function body in Abstract class.
    • Syntax for calling Abstract class Pure Virtual Function: baseAbstractClass::printClassName(); (See example)
    • Usage:
      • Sometime we can have common functionality to be performed by all derived classes in a Pure Virtual Function.
      • In such case, we can define common functionality in Abstract class's Pure Virtual Function body and call this function from other derived classes using above syntax.
      • This way, we are reusing the code properly.

AbstractClass_PureVirtualDestruct_Override.cpp

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
86
87
88
89
90
91
92
93
94
95
96
97
#include<iostream>
using namespace std;

class baseAbstractClass
{
  int someValue;
public:
  baseAbstractClass(int val):someValue(val) {	}
	
  // Override Method
  virtual void overridedFunction() {
    cout << "Override Base class Method\n";
  }

  // pure virtual function
  virtual void info() = 0;

  // pure virtual function with Function body
  // `g++ error: pure-specifier on function-definition`
  // but works fine in Visual Studio.
  // Recommendation: Do not implement Pure Virtual Function in Declaration itself,
  // We can define it outside class definition, as in case of virtual ~baseAbstractClass()
  // Pure Virtual Function body should be outside class definition is the Standard, but VC++ allows it somehow.
  virtual void printClassName() = 0
  {
    cout << "Class Name = baseAbstractClass" << endl;
  }

  // pure virtual destructor, it must be implemented otherwise we get linking error: 
  // `error LNK2019: unresolved external symbol "public: virtual __thiscall baseAbstractClass::~baseAbstractClass(void)"`
  // Implementation can be here itself just like printClassName() rather than outside declaration.
  virtual ~baseAbstractClass() = 0;
};

baseAbstractClass:: ~baseAbstractClass()
{
  cout << "Inside baseAbstractClass Destructor" << endl;
}

class derivedClass: public baseAbstractClass
{
public:
  derivedClass(int val):baseAbstractClass(val) {	}

  void derivedClassFunc()
  {
    cout << "Inside derivedClassFunc" << endl;
  }

  // `error C3668: 'derivedClass::overridedFunction' : method with override specifier 'override' did not override any base class methods`
  // The reason is `change in signature` of overrideFunction(), we have added a parameter here which is not the case in Base class
  void overridedFunction(int count) override
  {
    cout << "Overrided Derived class function\n";
  }

  // Without override identifier, we are free to change the virtual functions signature in derived class
  // this violates the very basic idea of declaring virtual method in base class. override identifier plays very good role here.
  void overridedFunction(float count)
  {
    cout << "Overrided Derived class function\n";
  }

  // Implementation of pure virtual function, a must for derivedClass
  virtual void printClassName() override
  {
    // calling Abstract Base class printClassName()
    baseAbstractClass::printClassName();
    cout << "Class Name = derivedClass" << endl;
  }

  // Implementation of pure virtual function, a must for derivedClass
  void info() override  // `error C2259: 'derivedClass' : cannot instantiate abstract class`
  {                     // This error appears, if we do not implement Pure Virtual `info()` in derivedClass.
    cout << "Inside Derived Class Info()" << endl;
  }
};

int main()
{
  baseAbstractClass *basePtr;
  derivedClass  derivedObj(20); // `error C2259: 'derivedClass' : cannot instantiate abstract class`
  basePtr = &derivedObj;        // This error appears, if we do not implement Pure Virtual `info()` in derivedClass.
  basePtr->info();
  cout << "-------------------------------------\n";
  basePtr->printClassName();
  cout << "-------------------------------------\n";

//  baseAbstractClass	baseObj(10);  // `error C2259: 'baseAbstractClass' : cannot instantiate abstract class`

  // to check Pure Virtual Destructor invocation
  baseAbstractClass *basePtr1 = new derivedClass(40);
  basePtr1->info();
  delete basePtr1;

  getchar();
}

override Identifier

  • It shows the reader of the code that this is a virtual method, that is overriding a virtual method of the base class.
  • The compiler also knows that it’s an override, so it can “check” that you are not altering/adding new methods that you think are overrides.
  • In below eaxample, in derived2 the compiler will issue an error for "changing the type".
  • Without override, at most some compiler would give a warning for "you are hiding virtual method by same name".
1
2
3
4
5
6
7
8
9
10
11
12
class base {
  public:
  virtual int foo(float x) = 0; 
};
class derived: public base {
   public:
   int foo(float x) override { ... do stuff with x and such ... }
}
class derived2: public base {
   public:
   int foo(int x) override { ... } 
};
References:
  • https://www.tutorialcup.com/cplusplus/polymorphism.htm