> Are virtual member functions and abstract base classes really necessary to learn right now
> before I continue trying to set up a hierarchy?
If you are programming with hierarchies, you would confront the need for virtual functions sooner than you anticipate right now. Abstract base classes can wait.
Since you have learnt about inheritance, you would already know that a reference (or pointer) to the derived class
Player could be substituted for a reference (or pointer) to the base class
Character. Once you know this much, understanding virtual functions is easy:
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
|
#include <iostream>
class base_class
{
public:
virtual ~base_class() {}
void non_virtual_function() const { std::cout << "base_class::non_virtual_function\n" ; }
virtual void virtual_function() const { std::cout << "base_class::virtual_function\n" ; }
};
struct derived_class : base_class
{
public:
// derived_class::non_virtual_function hides base_class::non_virtual_function
void non_virtual_function() const
{ std::cout << "derived_class::non_virtual_function hides base_class::non_virtual_function\n" ; }
// derived_class::non_virtual_function overrides base_class::non_virtual_function
virtual void virtual_function() const override
{ std::cout << "derived_class::virtual_function overrides base_class::virtual_function\n\n" ; }
};
void foo( const base_class& x )
{
// the static type (type known at compile-time) of the object referred to by 'x' is base_class
// the dynamic type (type known only at run-time, which may be different each time
// foo is called) of the object referred to by 'x' could be a class derived from base_class
x.non_virtual_function() ; // not virtual; bind to the function of the static type
// call 'base_class::non_virtual_function
// the same function is called every time
x.virtual_function() ; // virtual; bind to the function based on the the dynamic type
// call ????::virtual_function where ???? is the dynamic type of he object
// each time foo is called, this may be a different function
}
int main()
{
derived_class derived ;
foo(derived) ;
struct another : base_class
{
void non_virtual_function() const
{ std::cout << "*** main::another::non_virtual_function ***\n" ; }
virtual void virtual_function() const override
{ std::cout << "*** main::another::virtual_function ***\n\n" ; }
};
another a ;
foo(a) ;
}
|
http://coliru.stacked-crooked.com/a/3a150a85a65d6279
> Will I be thankful to know how to use them later
> on in development of this program, or can I get away with not knowing them for now?
Actually this is an excellent idea. Start writing your code as if virtual functions do not exist, keep with it till you encounter a situation where you observe that run-time dispatch based of the dynamic type of the object would be extremely handy. Learn about virtual functions at that point; see what a big difference the addition of a single keyword can make; apply that knowledge to your code; and that knowledge would become internalised, intuitive. In software, as in most other endeavours, we haven't really learnt something - be it a language or a library feature - till we have used it to solve a real life problem.
So go ahead, start writing your program.