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

时间:2016-07-15 18:05:36

标签: c++ inheritance override vtable name-hiding

#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()的调用。谁会被叫?叶子类型的f1()或叶子的f1()? 根据我的教学,编译器总是在左侧的类型中查找函数。 (Base * p2 = new Leaf(* p))但是在这里,我可以看到它转到了Leaf类的f1()。 我可以看到它是Leaf的,但不明白为什么......

感谢帮助者!

1 个答案:

答案 0 :(得分:2)

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

要理解为什么它被称为Derived :: f1(),你可能需要知道&#34; C ++名称隐藏在继承&#34;中,你可以参考一些在线文章如:

您还需要了解&#34;非限定名称查找&#34;您可以参考&#34;会员功能定义&#34;此网页中的部分:Unqualified name lookup

总之,主要观点是:

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

通话过程应如下:

  1. 在main()中,p2->f1();被执行。
  2. 因为p2是指向Base的指针,所以&#34; f1&#34;的名称在Base的方法列表中搜索。
  3. 请注意,Base :: f1()是 NOT 虚拟,因此调用Base :: f1()(&#34; Base :: f1()&#34; < /强>)。是的,f1()在Derived中声明为虚拟,但这不会影响Base的虚拟表。
  4. Base :: f1()调用f2,它是Base的虚方法。由于f2仅在Derived中被覆盖,因此Derived :: f2()实际上被称为(&#34; Derived :: f2()&#34; )。
  5. Derived :: f2()调用f1()实际上是Derived :: f1()。因为Derived :: f1()被声明为虚拟并在Leaf中被覆盖,所以最终调用的是Leaf :: f1()(&#34; Leaf :: f1()&#34; )。
  6. Leaf :: f1()调用f3(),它是Leaf :: f3()。 f3()是一个只有叶子才能被调用的方法(&#34; Leaf :: f3()&#34; )。