通过 Derived::f2() 调用 f1() 时调用了谁的函数?

Who's function get called when calling f1() through Derived::f2()?

#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; 
}

您好,

这道题是一道考试题,但我很难找到正确的描述方式并在网上查找。

在线:

p2->f1(); 

输出为:

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

在 Derived f2() 中调用了 f1()。谁会被召唤? Base 类型的 f1() 还是 Leaf 类型的 f1()? 据我所知,编译器总是在左边的类型中寻找函数。 (Base* p2 = new Leaf(*p) ) 但是在这里我可以看到它转到 class Leaf 的 f1()。 我可以看出这是 Leaf 的,但不明白为什么...

感谢帮助!

快速回答您的问题:Derived::f1() 在 Derived::f2() 中被调用。

要理解为什么调用Derived::f1(),您可能需要"C++ name hiding in inheritance"的知识,您可以参考一些在线文章,如:

你还需要"Unqualified name lookup"的知识,你可以参考本网页的"Member function definition"部分:Unqualified name lookup.

综上所述,主要有以下几点:

  • 对于您的代码,Derived::f1() 隐藏了 Base::f1(),这意味着 Base::f1() 对 Derived 的成员不可见。
  • 对 f1() 的调用是一个不合格的名称查找案例。
  • 名字一般是从最里面的范围向外查找的。当在 Derived::f2() 中调用 f1() 时,编译器首先在最内部的范围内查找,即 Derived::f2() 主体本身;然后是整个 class Derived 范围。因为可以在 Derived 的范围内找到 f1(),所以它成为被调用的那个。
  • 您可能会认为 Base::f1() 看起来像与 Derived::f1() 处于同一级别,因为继承,然后想知道为什么 Base::f1() 不是叫。召回名称隐藏。

调用的过程应该是这样的:

  1. 在main()中,执行了p2->f1();
  2. 因为p2是指向Base的指针,"f1"的名字在Base的方法列表中查找
  3. 注意 Base::f1() 是 NOT 虚拟的,所以 Base::f1() 被调用("Base::f1()").是的,f1()在Derived中声明为virtual,但这并不影响Base.table的virtual
  4. Base::f1() 调用 f2,它是 Base 的虚方法。因为 f2 仅在 Derived 中被覆盖,所以 Derived::f2() 是实际调用的那个 ("Derived::f2()").
  5. Derived::f2() 调用 f1() 实际上是 Derived::f1()。因为Derived::f1()在Leaf中被声明为virtual并被覆盖,所以最终调用的是Leaf::f1()("Leaf::f1()").
  6. Leaf::f1() 调用 f3() 即 Leaf::f3()。 f3() 是 Leaf 才有的方法,所以它只是被调用("Leaf::f3()").