Inheritance/Polymorphism  «Prev  Next»
Lesson 10 C++ Virtual Functions
Objective This page contains several guidelines for virtual functions along with several rules.

Several Guidelines for Virtual function with Rules

List several rules for working with virtual functions

Here are several rules and guidelines for working with virtual functions:
  1. Only nonstatic member functions can be virtual.
  2. The virtual characteristic is inherited. Thus, the derived class function is automatically virtual, and the presence of the virtual keyword is usually omitted.
  3. Constructors cannot be virtual.
  4. Destructors can be virtual. As a rule of thumb, any class having virtual functions should have a virtual destructor.

C++ Object Construction

In C++, a complete object is constructed one base class at a time.
If we have a base class B and a class D derived from B. When constructing a D object, while executing B's constructor, the dynamic type of the object under construction is B. In particular, a call to a virtual function B:: Fun will hit B's definition of Fun, regardless of whether D overrides it or not.
Calling a D member function when the D object's members have not even been initialized yet would lead to unpredictable results.
Only after the construction of B has completed is D'sconstructor body executed and its identity as a D established. As a rule of thumb, keep in mind that during B's construction there is no way to tell whether the B is a standalone object or a base part of some other further-derived object; virtually-acting virtual functions would be such a way.
a call from a constructor to a pure virtual function that is not defined at all has undefined behavior. Such code is therefore not only confusing, but it is also more fragile in the face of maintenance. On the other hand, some designs ask for post-construction, which is a virtual function that must be invoked right after the full object has been constructed.

Virtual Functions

A virtual function is a member function that is declared within a base class and redefined by a derived class. To create a virtual function, precede the function's declaration in the base class with the keyword virtual. When a class containing a virtual function is inherited, the derived class redefines the virtual function to fit its own needs. In essence, virtual functions implement the "one interface, multiple methods" philosophy that underlies polymorphism. The virtual function within the base class defines the form of the interface to that function. Each redefinition of the virtual function by a derived class implements its operation as it relates specifically to the derived class. That is, the redefinition creates a specific method.
When accessed "normally," virtual functions behave just like any other type of class member function. However, what makes virtual functions important and capable of supporting run-time polymorphism is how they behave when accessed via a pointer.
A base-class pointer can be used to point to an object of any class derived from that base. When a base pointer points to a derived object that contains a virtual function, C++ determines which version of that function to call based upon the type of object pointed to by the pointer. And this determination is made at run time. Thus, when different objects are pointed to, different versions of the virtual function are executed. The same effect applies to base-class references. To begin, examine this short example:

#include <iostream>
using namespace std;
class base {
 public:
  virtual void vfunc() {
  cout << "This is base's vfunc().\n";
 }
};
class derived1 : public base {
 public:
  void vfunc() {
   cout << "This is derived1's vfunc().\n";
  }
};
class derived2 : public base {
 public:
  void vfunc() {
   cout << "This is derived2's vfunc().\n";
  }
};
int main(){
 base *p, b;
 derived1 d1;
 derived2 d2;
 // point to base
 p = &b;
 p->vfunc(); // access base's vfunc()
 // point to derived1
 p = &d1;
 p->vfunc(); // access derived1's vfunc()
 // point to derived2
 p = &d2;
 p->vfunc(); // access derived2's vfunc()
 return 0;
}

This program displays the following:
This is base's vfunc().
This is derived1's vfunc().
This is derived2's vfunc().