Non-Virtual Methods

Omitting the virtual keyword declares a method as non-virtual. Simply speaking, declaring a method as virtual enables overriding, declaring a method as non-virtual disables overriding.


  theAccount->display();

The display() method that is called depends on whether theAccount pointer references a generic Account, Deposit account or Current account (the dynamic type - sometimes called late binding).

So why are non-virtual methods required? If in the rare circumstance of declaring a class that you know will have no derived classes, you can use non-virtual methods. When virtual methods are used the compiler does not know for certain the type of an object until run-time, so the compiler inserts additional code to evaluate the dynamic type at run-time and call the correct method. Removing this feature allows slightly faster program execution. Non-virtual can also be used if for some reason you wish that a method cannot be over-ridden (e.g. the constructor of an object).

Most Object Oriented Programming languages only support virtual methods, but strangely enough in C++ non-virtual is the default setting!

So in the Virtual case:

  ...
 
  class Account{
    public:
      virtual string getType() { return "Generic Account"; };
  };

  class Current: public Account{
    public:
      virtual string getType() { return "Current Account"; };  
  };

  class Deposit: public Account{
    public:
      virtual string getType() { return "Deposit Account"; };  
  };
 
  int main()
  {
    // Note that all pointers have the static type Account
    Account *a = new Account(); 
    Account *b = new Current();
    Account *c = new Deposit();

    cout << "Pointer a Displayed: " << a->getType() << endl;
    cout << "Pointer b Displayed: " << b->getType() << endl;
    cout << "Pointer c Displayed: " << c->getType() << endl;
  }
  

(The full source code for this "virtual" example is here - NonVirtualTest.cpp) This program will result in the output:


 Pointer a Displayed: Generic Account
 Pointer b Displayed: Current Account
 Pointer c Displayed: Deposit Account

Since the getType() method is virtual the getType() method most closely associated with the object will be called, not the getType() method associated with the pointer. Note that you only need to declare the method as virtual in the base class declaration and it will be virtual in all child classes, regardless if the virtual keyword is used or not. Redefining a virtual method is called overriding.

In the non-virtual case:

  ..
  
  class Account{
    public:
      string getType() { return "Generic Account"; };
  };

  class Current: public Account{
    public:
      string getType() { return "Current Account"; };  
  };

  class Deposit: public Account{
    public:
      string getType() { return "Deposit Account"; };  
  };
 
  int main()
  {
    Account *a = new Account();
    Account *b = new Current();
    Account *c = new Deposit();

    cout << "Pointer a Displayed: " << a->getType() << endl;
    cout << "Pointer b Displayed: " << b->getType() << endl;
    cout << "Pointer c Displayed: " << c->getType() << endl;
  }

(The full source code for this "non-virtual" example is here - NonVirtualTest2.cpp) This program will result in the output:


 Pointer a Displayed: Generic Account
 Pointer b Displayed: Generic Account
 Pointer c Displayed: Generic Account

Since the methods are now non-virtual the getType() associated with the pointer will always be called. So, the Account::getType() will always be called.

The destructor is always virtual as we require different actions in destructing an object, for example in:

So, for example:

 
  class Deposit :: public Account
  {
      //states
    
    public:
      
      virtual ~Deposit(); //destructor - always virtual
  };

  Deposit::~Deposit() 
  {
    //calculate interest
    //send statement.
  }