1
#include <iostream>
#include <string>
using namespace std;

class Base {
public:
 Base(const string& s): str(s) {cout<<"Base::ctor\n";}
 Base(const Base& b): str(b.str) {cout<<"Base::copy ctor\n";}
 virtual ~Base() {cout<<"Base::dtor\n";}
 void f1() {cout<<"Base::f1()\n"; f2();} //2 orders
 virtual void f2() {cout<<"Base::f2()\n";}

private:
 string str;
};

class Derived : public Base {
public:
 Derived(const string& s): Base(s)
 {cout<<"Derived::ctor\n";}
 Derived(const Derived& d): Base(d)
 {cout<<"Derived::copy ctor\n";}
 ~Derived() {cout<<"Derived::dtor\n";} 
 virtual void f1() {cout<<"Derived::f1()\n"; f2();}
 void f2() {cout<<"Derived::f2()\n"; f1();} //jumps from here to Leaf's f1()
};

class Leaf : public Derived {
public:
 Leaf(const string& s): Derived(s)
 {cout<<"Leaf::ctor\n";}
 Leaf(const Leaf& dd): Derived(dd)
 {cout<<"Leaf::copy ctor\n";}
 ~Leaf() {cout<<"Leaf::dtor\n";}
 void f1() {cout<<"Leaf::f1()\n"; f3();}
 void f3() {cout<<"Leaf::f3()\n";}
};


int main() {
 Leaf * p = new Leaf("Hello");
 Base * p2 = new Leaf(*p);

 p2->f1();

 delete p2;
 delete p;
 return 0; 
}

Hello,

This question is an exam phrased one but it's very hard for me to find the right way to describe it and look for it online.

in line :

p2->f1(); 

the output is:

 Base::f1()
 Derived::f2()
 Leaf::f1()
 Leaf::f3()

in Derived f2() there's a call for f1(). who's going to be called? f1() of the type Base or f1() of Leaf? From what I have been taught, the compiler always looks for the function in the type to the left. (Base* p2 = new Leaf(*p) ) But over here I can see that it goes to f1() of class Leaf. I can see that it is Leaf's but don't understand why...

thanks for the helpers !

curiousguy
  • 8,038
  • 2
  • 40
  • 58
EilonBom
  • 25
  • 7

1 Answers1

2

To answer your question quickly: Derived::f1() is called in Derived::f2().

To understand why it's Derived::f1() that's called, you probably need the knowledge of "C++ name hiding in inheritance", which you can refer to some online articles like:

You also need the knowledge of the "Unqualified name lookup" which you can refer to the "Member function definition" section in this web page: Unqualified name lookup.

In summary, the major points are:

  • In the case of your code, Derived::f1() hides the Base::f1() which means Base::f1() is not visible to the members of Derived.
  • The call to f1() is an unqualified name lookup case.
  • Names are generally looked up from the most inside scope to the outside. When f1() is called in Derived::f2(), the compiler first looks up in the most inside scope, which is the Derived::f2() body itself; then the entire class Derived scope. Because f1() can be found in the scope of Derived, it becomes the one that's called.
  • You might think that Base::f1() looks like to be sitting in the same level with Derived::f1() because of the inheritance and then wonder why Base::f1() is not called. Recall name hiding.

The process of the call should be as follows:

  1. In the main(), p2->f1(); is executed.
  2. Because p2 is a pointer to Base, the name of "f1" is searched in Base's method list.
  3. Note that Base::f1() is NOT virtual, so Base::f1() is called ("Base::f1()"). Yes, f1() is declared as virtual in Derived, but this doesn't affect the virtual table of Base.
  4. Base::f1() calls f2 which is a virtual method of Base. Because f2 is only overridden in Derived, Derived::f2() is the one that's actually called("Derived::f2()").
  5. Derived::f2() calls f1() which is actually Derived::f1(). Because Derived::f1() is declared as virtual and overridden in Leaf, it is Leaf::f1() that is eventually called("Leaf::f1()").
  6. Leaf::f1() calls f3() which is Leaf::f3(). f3() is a method that only Leaf has so it is just called("Leaf::f3()").
Community
  • 1
  • 1
yaobin
  • 2,436
  • 5
  • 33
  • 54
  • Thank you yaobin! very helpful... So my conclusion is that if a method is called in a class (for example Derived), it will call the same classes method - meaning Derived::f2() (and then if there's an inheritance etc...) ? – EilonBom Jul 15 '16 at 18:26
  • @EilonBom I edited my answer and added some references that you can look into. Hopefully they can give you a better understanding of what happens behind the scene. This should address your questions in both the post and the comment. – yaobin Jul 15 '16 at 19:07
  • "the address of f1 is searched" <-- There's no address searching going on, we're doing name lookup. – Barry Jul 15 '16 at 19:14
  • @Barry Yeah, I was not wording that properly. I have edited my answer and changed it to "the name of 'f1' ". – yaobin Jul 15 '16 at 19:17
  • @yaobin Doesn't have to be the method list either. `f1` could be a member variable. – Barry Jul 15 '16 at 19:28