More about Virtual and Polymorphism
Objectives
Notes
By default, class member functions are not virtual
This means that there is probably one instance of the function
And when the function is invoked, the one instance is called.
IE the function address is probably stored in the class.
When a class "overrides" a non-virtual function
The new address is saved
But you can get to the base function with BaseClassName::MethodName()
In either case, the function to call is hard coded in the class.
The cool thing is, I can pass a pointer to a base class, that is actually a pointer to a derived class.
If I pass a pointer to a base class, the base class function is called.
If a member function is not virtual, the base class function will be called for the derived class as ell.
We will investigate this further later.
When a class contains a virtual function
The compiler constructs a vtable or virtual table
This has a pointer for each of the virtual members.
The vtable allows us to pass a pointer to a base class, but look up the correct member function to use.
This is the main mechanism of polymorphism.
Pure Virtual Functions and Abstract Base Classes
Remember, one of the reasons we build a hierarchy is to enforce a common interface.
But sometimes we don't know how to implement the method in any way for the base class.
So, as we saw last program, we mark it virtual by setting it equal to 0.
This builds an Abstract Base Class with a Pure Virtual Function.
You can not make an instance of an abstract base class.
And you must provide a overriding function for any pure virtual functions.
On constructors
Constructors are called in this order
The base constructor
The derived constructor
You should NEVER make a virtual constructor.
If there are any derived classes between the base and the end, each of their constructors are called as well.
Initializer lists
We can initialize a variable in the function header
We can also do this in the body of the constructor
But the second is really not initialization
All member variables are constructed BEFORE the constructor is called.
Sometimes, like calling the base constructor with parameters, we need to initialize something as it is constructed.
To do this we use an initializer list.
Initializer list syntax
Constructor(param, param, ...) : member1{initialize}, member2{initialize}, ... { body}
The member values must be initialized in the order they are declared.
The base constructor can be called there as well.
We need to use this if there is no default constructor in a base class.
On destructors
The base class destructor will be called after the class destructor.
This needs to be called if there is dynamic memory involved ANYWHERE
You should always declare the distructor virtual in a base class.
For other member functions
Making them virtual is safe but slower (only slightly)
Make them virtual if you think they may be overridden
If there is no chance, do not make them virtual.
In NewPlayerT.h
This has an abstract base class.
Fight() is designed to be overridden, everything will fight in a different manner.
Only the derived classes can get at the SetDefense function.
Note the virtual destructor in the base class.
It does nothing, but the compiler REALLY wants you to have one.
In NewPlayerT.cpp
Note the ctor initializes that call the base constructor.
In newPlayerTest.cpp
Note the array of pointers.
Note TellAboutPlayer
This is Polymorphism!