An intriguing C++ quiz that might challenge you more than you think

I was recently looking through my university days archive (ahh the days when I found learning surface integrals exciting) and came across this following problem that I created for myself trying to understand how C++ inheritance works. It was not obvious to me back then and I remember that even for TAs and some developers it was not very clear what was the deal, with some getting the answer right but not the why. I still find it intriguing today so I decided to share it, hoping that it may also be intriguing for others.

I will first show the problem. Try to answer it for yourself and post the solution in the comments if you want. Afterwards you can scroll down for a complete explanation and see if you were right.

The problem

Assume that we have the following two very simple classes:

class Parent {
  public:
  virtual void print(){ 
    std::cout<<"I am the parent class"<<std::endl; 
  }
};

class Derived : public Parent {
  public:
  virtual void print(int x){ 
    std::cout<<"I am the derived class"<<std::endl;
  }     
};

What will each of the following two small pieces of code do and why?

int main(){
  Derived *derived=new Derived;
  derived->print();
  return 0;
}  

int main(){
  Parent *derived = new Derived;
  derived->print();
  return 0;
}  

That is it. I know that maybe for some of you this is completely obvious so then just consider it a validation of your knowledge. For the others try to answer and then go to the next section to see if you got it right.

The solution

  • The first case fails
  • The second case will print: "I am the parent class"

The first example has to do with the dominance(or name hiding) mechanism. What that means is that a declaration of a function in a derived class will hide all ancestral functions, regardless of their signature. This surprises some, but the reason for this is that name lookup precedes overload resolution and they are independent steps in the compilation process. So in our case even though there is a function in the Parent class that matches the signature of the function we are calling in main(), the compiler never considers it. In the end we get error: no matching function for call to 'Derived::print()'.

Now the question comes...why didn't the second one also fail, since we are still using a Derived object to call print()?

The key here is that name lookup does not start with the actual type of the object, but with the declared type of the object. In other words it starts with the type of the variable which references/points to the actual object. In our second case we have a Derived object being stored(yeah I know, its address) in a Parent pointer variable, so our compiler will look in the Parent class for the print() function. It does find it and compilation succeeds correctly and at runtime we get the corresponding output.

I hope you found this as interesting as me and see you next time for, I hope, a much longer and full of content post.