Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ multi level inheritance with virtual functions [duplicate]

Tags:

c++

c++17

I am a bit confused about multi-level inheritance and virtual functions in C++. In the example below, I have 3 levels with Bottom inheriting from Middle inheriting from Top.

If I declare the function in Top as virtual and use a pointer of type Middle, it still overrides the function declared in Middle even though it's not declared virtual.

I was expecting:

Middle* ptr = new Bottom();
ptr->hello(); // Expectation: "Hello Middle"  (Actual: "Hello Bottom")

and

Top* ptr = new Bottom();
ptr->hello(); // "Hello Bottom"

But that doesn't seem to be the case. Why is this?

Full code:

#include <iostream>

//  Top
//   ^
// Middle
//   ^
// Bottom

struct Top {
  // This is set to virtual.
  virtual void hello() { std::cout << "Hello Top\n"; }
};

struct Middle : public Top {
  // But not this.
  void hello() { std::cout << "Hello Middle\n"; }
};

struct Bottom : public Middle {
  // So why is this called if the type is Middle?
  void hello() { std::cout << "Hello Bottom\n"; }
};

int main() {
  Middle *ptr = new Bottom(); // Will use hello() in Bottom.
  // Top *ptr = new Bottom(); // Same result as the above.
  ptr->hello();
  delete ptr;
  return 0;
}
like image 234
Plasty Grove Avatar asked Sep 21 '19 17:09

Plasty Grove


1 Answers

Derived functions are virtual no matter you specify them virtual or not if the base function was virtual:

If some member function vf is declared as virtual in a class Base, and some class Derived, which is derived, directly or indirectly, from Base, has a declaration for member function with the same

name parameter type list (but not the return type) cv-qualifiers ref-qualifiers Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).


If you wanted to access the base functions you can use:

ptr->Top::hello();

Middle* ptr2 = new Bottom();
ptr2->Middle::hello();

delete ptr;
delete ptr2;

Live on godbolt

like image 103
Oblivion Avatar answered Nov 15 '22 09:11

Oblivion