Declaration of virtual must be in base class

Quote:

“If you are calling a virtual function via a pointer to a Base class, the vtable will resolve the call to the function of the most derived class.”

Correct? Well not quite!

Here is the following example where identifyFromBase() and identifyFromDerived() both call the function id() which is declared virtual. Will those two functions resolve to the same version of id()?

struct VikiBase {
  void id() { std::cout << "id: Base \n"; }

  void identifyFromBase() {
    std::cout << "identifyFromBase() \n";
    this->id();
  }
};

struct VikiDerived : public VikiBase {
  virtual void id() { 
    std::cout << "id: Derived \n"; }

  void identifyFromDerived() {
    std::cout << "identifyFromDerived() \n";
    this->id();
  }
};

struct VikiFinal : public VikiDerived {
  void id() override { std::cout << "id: Final \n"; }
};

Usage:

	VikiFinal vif;
	vif.identifyFromBase();		
	vif.identifyFromDerived()

Output:

	identifyFromBase()
	id: Base
	identifyFromDerived()
	id: Final

Surprise! The function identifyFromBase() calls the id() function declared in VikiBase. This seems to confuse some people, as they expect the declaration of “virtual void id()” in VikiDerived will propagate to the parent class. In fact, it won’t. When the compiler constructs the VikiBase object, identifyFromBase() will only see the address of the id() function from VikiBase, and the address of this function will be compiled into the code. The object VikiDerived will not “reconstruct” the VikiBase object, but rather just inherit from it. At the time the function identifyFromBase() was compiled, the vtable didn’t exist, so it can’t resolve to anything other than the id() from VikiBase!

Best practice: if you intend to declare a function as virtual, do it at the lowest level (Base) class. If you can’t do that for some reason, it is often a better idea to declare a different function and use that function in all derived classes from then on.

Leave a Reply

Your email address will not be published. Required fields are marked *