C++ function calls across inheritance layers

Hi There,

I’m reviewing some code in a project that I didn’t write and noticed that I have a complicated set of function calls across base and derived classes. The general structure is as follows:

class Parent 
{
public: 
  void foo (buffer) 
  {
   //do some stuff 
   bar(args) 
  } 
  void bar (args) 
  {
   //execute some version of "bar" 
  }

//...other stuff
}
class Child : public Parent
{
public: 
 void bar (args) 
 {
     //slightly different version of "bar"
 }
//...other stuff
}

Note that 1) The parent definition of foo calls bar and 2) both the parent and child have bar defined with the same return type and arguments.

Then, in another area of the code there is essentially the following:

Child childInstance 

childInstance.foo(buffer) 

Since no definition exists for Child::foo I assume that this gets reffered to Parent::foo, but then INSIDE parent foo I need to know if the the call to bar gets linked to the Parent or Child definition of bar. It seems from setting breakpoints that indeed the Child definition gets called here but I was wondering if there’s a general principle I can refer to here, or some good references for better understanding the reasons that this works and that C++ (maybe the linker is what’s relevant here?) doesn’t get confused between the child and parent implementations of bar.

You know what, I just realized Child::bar is marked override which I think answers my own question here…

Not sure what kind of crazy compiler you are using, but in my world, you neither have bar marked as override, nor is that possible since bar is not marked virtual in Parent, nor is therefore bar in Child called, as the parent object has no way of know the correct child pointer without a vtable.

In c++ if you don’t mark a function as virtual, the function call cannot be redirected to a different object.

1 Like

Oops yeah sorry my mistake. I should have said: The equivalent code in my project has the Child::bar function marked with override

And indeed the Parent::bar equivalent is marked virtual. This answers all the questions, I neglected to read carefully enough here and got turned around tracing the function calls. Thank you! The corrected code (which should resolve any ambiguities) would look like

class Parent 
{
public: 
  void foo (buffer) 
  {
   //do some stuff 
   bar(args) 
  } 
  virtual void bar (args) 
  {
   //execute some version of "bar" 
  }

//...other stuff
}
class Child : public Parent
{
public: 
 void bar (args) override
 {
     //slightly different version of "bar"
 }
//...other stuff
}

Yep looks good. Be aware, that if you are storing a child instance inside e.g. a Parent unique_ptr, you need to make Parent destructor virtual too. Otherwise, you will be leaking Child objects.

1 Like

the Parent destructor in this project is marked virtual, so it seems like the author was aware of this. However the Child instance is just stored as a member inside another class altogether. No unique_ptr or anything. Can you explain why the virtual marker is necessary in the Parent destructor?

When the child instance is destroyed with the parent pointer, parent destructor would be called (as per usual). If the destructor is not virtual, this destructor call would not be redirected to child but just destruct parent and that is that. Child destructor never called and therefore leaked.

3 Likes