通过 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"的知识,您可以参考一些在线文章,如:
- What is name hiding in C++?
- Why does an overridden function in the derived class hide other overloads of the base class?
你还需要"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() 不是叫。召回名称隐藏。
调用的过程应该是这样的:
- 在main()中,执行了
p2->f1();
。
- 因为p2是指向Base的指针,"f1"的名字在Base的方法列表中查找
- 注意 Base::f1() 是 NOT 虚拟的,所以 Base::f1() 被调用("Base::f1()").是的,f1()在Derived中声明为virtual,但这并不影响Base.table的virtual
- Base::f1() 调用 f2,它是 Base 的虚方法。因为 f2 仅在 Derived 中被覆盖,所以 Derived::f2() 是实际调用的那个 ("Derived::f2()").
- Derived::f2() 调用 f1() 实际上是 Derived::f1()。因为Derived::f1()在Leaf中被声明为virtual并被覆盖,所以最终调用的是Leaf::f1()("Leaf::f1()").
- Leaf::f1() 调用 f3() 即 Leaf::f3()。 f3() 是 Leaf 才有的方法,所以它只是被调用("Leaf::f3()").
#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"的知识,您可以参考一些在线文章,如:
- What is name hiding in C++?
- Why does an overridden function in the derived class hide other overloads of the base class?
你还需要"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() 不是叫。召回名称隐藏。
调用的过程应该是这样的:
- 在main()中,执行了
p2->f1();
。 - 因为p2是指向Base的指针,"f1"的名字在Base的方法列表中查找
- 注意 Base::f1() 是 NOT 虚拟的,所以 Base::f1() 被调用("Base::f1()").是的,f1()在Derived中声明为virtual,但这并不影响Base.table的virtual
- Base::f1() 调用 f2,它是 Base 的虚方法。因为 f2 仅在 Derived 中被覆盖,所以 Derived::f2() 是实际调用的那个 ("Derived::f2()").
- Derived::f2() 调用 f1() 实际上是 Derived::f1()。因为Derived::f1()在Leaf中被声明为virtual并被覆盖,所以最终调用的是Leaf::f1()("Leaf::f1()").
- Leaf::f1() 调用 f3() 即 Leaf::f3()。 f3() 是 Leaf 才有的方法,所以它只是被调用("Leaf::f3()").