Once more, I’ll write a few words on virtual functions, as they are often confusing for myself. In C++ they exhibit an interesting behavior (by definition!) when casting from one class to another, that can be confusing if one isn’t very fond of the properties of a virtual function. In particular, in C++, virtual functions inside objects behave as being of the type they have been instantiated as, not as the types they may be converted to (by casting) throughout your code.
Take the following example:
#include <iostream> using namespace std; class A { public: virtual void Run() { cout << "A::Run" << endl; } void Yoke() { cout << "A::Yoke" << endl; } }; class B : private A { public: virtual void Run() { cout << "B::Run" << endl; } void Yoke() { cout << "B::Yoke" << endl; } };
Now, let us try to use classes A and B normally:
int main() { A* a = new A(); B* b = new B(); a->Run(); b->Run(); return 0; }
As one would expect, the result is A::Run and B::Run, normally. Function “Run” from class B overloads function “Run” inside class A, hence this behavior. Now let’s see what happens when we cast from one class to another.
int main() { A* a = new A(); B* b = ( B* )a; b->Run(); return 0; }
Calling the “Run” function, perhaps surprisingly, invokes the Run method of class A and outputs “A::Run()”. Although the type of variable b is a B*, in truth it is an instance of class A. What virtual functions are supposed to do is, lookup the real object type (meaning: the class with which they were instantiated), and call THAT function. The “b” variable was instantiated as A and hence this behavior.
This behavior is often desired. It is used when a parent class wants to call a function that can be overloaded; in that case, all the developer needs to do is instantiate the object using the child class. Take the following example, where this behavior helps:
class Foo { void Go() { cout << "Foo::Go" << endl; this->Run(); } virtual void Run() { cout << "Running as Foo" << endl; } } class Bar : private Foo { void Run() { cout << "Running as Bar" << endl; } } int main() { Bar* bar = Bar(); bar->Go(); }
While class Bar offers a generalized behavior in function Go, it allows specialization, if the derived class desires, by making its Run function virtual. Notice that the proper function is invoked because the instantiation is done as Bar, not as Foo, even though the Go function is defined within Foo.
Sometimes, however, this behavior is not desired. Take, for the sake of illustration, as an example, a base class which is instantiated by a library that is unaware of possible class extensions, and returned by one of its functions or passed as an argument to a user-defined callback function. Having that type of object, the user might desire to cast it to a different type, a derived class, which they could want to be specialized, by defining this special behavior in an overloaded function called by the parent.
In some cases, it is possible to solve this problem by simply making functions non-virtual. This allows the program to execute the functions based on variable types (casted or defined types), and not actual object types (instantiated type). Yet another way to do it is to define a constructor for the derived class that accepts the base class as an argument and instantiates accordingly. The latter method might not always be possible, however, depending on the context.
I hope this post made some things about virtual functions clearer