这与函数重载有什么关系?

Wak*_*zil 7 c++ overriding overloading c++11

基本上是Item 21. Overriding Virtual FunctionsHerb Sutter的书中给出的例子的副本Exceptional C++.

#include <iostream>
#include <complex>
using namespace std;
class Base
{
public:
    virtual void f(int);
    virtual void f(double);
    virtual ~Base() {};
};

void Base::f(int) { cout << "Base::f(int)" << endl; }
void Base::f( double ) { cout << "Base::f(double)" << endl; }

class Derived: public Base {
public:
    void f(complex<double>);
};

void Derived::f(complex<double>) { cout << "Derived::f(complex)" << endl; }

int main()
{
    Base* pb = new Derived;
    pb->f(1.0);
    delete pb;
}
Run Code Online (Sandbox Code Playgroud)

代码打印Base::f(double),我没有问题.但我无法理解作者在第122页的顶部给出的解释(重点是我的):

有趣的是,即使Base*pb指向Derived对象,它也会调用Base :: f(double),因为重载解析是在静态类型(此处为Base)上完成的,而不是动态类型(此处为Derived).

我的理解是,该呼叫pb->f(1.0)是虚拟呼叫,Base::f(double)是最终置换器f(double)Derived.这与函数重载有什么关系?

Jon*_*Jon 12

这里微妙的部分是虚方法是一种调度函数调用的机制,而重载是一种影响调用解析的特性.

也就是说,对于任何调用,编译器需要确定应该调用哪个方法(解析它); 之后,在逻辑上不同的操作中,它需要生成调用该方法的正确实现的代码(调度它).

从定义BaseDerived上面给出我们可以很容易的理由是如果f(double)上调用Base*,则调用应(如适用)优先于基实现分派到任何派生覆盖.但回答这个回答的问题完全不同于

当源说pb->f(1.0),f 应该使用哪个方法来解析方法调用?

正如Sutter解释的那样,规范说当解析调用时,编译器将查看在f指向的静态类型上声明的方法pb; 在这种情况下,静态类型是Base*如此重载(不是覆盖!)声明Derived将不会被考虑.但是,如果调用解析的方法是virtual,Derived则将按预期使用提供的可能实现.

  • 实际上它必须是这样的 - 你可能没有实际派生虚函数声明的源代码,实际上可能还没有编写覆盖函数,所以(a)你无法得到它的默认值无论如何,(b)即使你可能,你的默认值在运行时动态地改变为你永远无法测试的值可能会非常令人惊讶. - 顺便说一下,我对你引用的文字有所改进的一点是,说"名字查找"而不是"重载决议"更正确,但分析是正确的,结果是一样的. (3认同)