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

你好,

这个问题是一个考试用词,但我很难找到正确的方式来描述它并在网上寻找它。

排队 :

p2->f1(); 

输出是:

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

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

感谢帮手!

4

1 回答 1

2

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

要理解为什么会调用 Derived::f1() ,你可能需要“C++ 名称隐藏在继承中”的知识,可以参考一些网上的文章,例如:

您还需要“不合格名称查找”的知识,您可以参考本网页中的“成员函数定义”部分:不合格名称查找

总结起来主要有以下几点:

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

调用过程应该如下:

  1. 在 main() 中,p2->f1();被执行。
  2. 因为 p2 是指向 Base 的指针,所以在 Base 的方法列表中搜索“f1”的名称。
  3. 请注意 Base::f1()不是虚拟的,因此 Base::f1() 被称为(“Base::f1()”)。是的,f1() 在 Derived 中被声明为 virtual,但这并不影响 Base 的虚拟表。
  4. Base::f1() 调用 f2,它是 Base 的一个虚方法。因为 f2 仅在 Derived 中被覆盖,所以 Derived::f2() 是实际调用的那个(“Derived::f2()”)。
  5. Derived::f2() 调用实际上是 Derived::f1() 的 f1()。因为 Derived::f1() 在 Leaf 中被声明为虚拟并被覆盖,所以最终调用的是 Leaf::f1() ( "Leaf::f1()" )。
  6. Leaf::f1() 调用 f3(),即 Leaf::f3()。f3() 是一种只有 Leaf 拥有的方法,所以它被称为(“Leaf::f3()”)。
于 2016-07-15T18:23:36.120 回答