Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这与函数重载有什么关系?_C++_C++11_Overloading_Overriding - Fatal编程技术网

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

C++ 这与函数重载有什么关系?,c++,c++11,overloading,overriding,C++,C++11,Overloading,Overriding,基本上是第21项中给出的示例的副本。重写Herb Sutter的书中的虚拟函数 #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 << "B

基本上是
第21项中给出的示例的副本。重写Herb Sutter的书中的虚拟函数

#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;
}
#包括
#包括
使用名称空间std;
阶级基础
{
公众:
虚空f(int);
虚空f(双);
虚~Base(){};
};

void Base::f(int){cout这里的微妙之处在于虚拟方法是分派函数调用的机制,而重载是影响调用解析的特性

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

根据上面给出的
Base
Derived
的定义,我们可以很容易地推断,如果
f(double)
Base*
上被调用,那么调用应该被调度到任何派生覆盖(如果适用)但回答这个问题与回答一个完全不同的问题

当源代码显示
pb->f(1.0)
时,哪些方法名为
f
是否应用于解析方法调用


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

此示例之所以有趣,是因为如果
pb
派生的*
而不是
Base*
,或者如果编译器能够以某种方式使用动态类型而不是静态类型来执行重载解析,那么它会将对
pb->f(1.0)
的调用与
void-Derived::f(complex)
匹配(
complex
可以从
double
隐式构造)这是因为派生类中名为
f
的函数有效地隐藏了同名的任何基类重载,即使它们的参数列表不同。但由于
pb
的静态类型实际上是
base*
,因此不会发生这种情况。

在本例中,尽管
virtual
,根本没有方法重写;派生类中的方法
f
不会重写基类中的任何方法,因为参数类型不匹配。在这种情况下,
pb->f
的调用无法调用(unique)方法
Derived::f
。重载解析/名称查找(只考虑静态类型
pb->f
的方法)必须在声明为
Base::f
的两个方法之间进行选择,在示例中,它将选择参数类型为
double
的方法。(在运行时,如果在与
派生的
不同的派生类中定义了一个重写,并且修改了示例,使得
pb
可能指向另一个派生类的对象,则这可能会最终调用重写。)


另一个问题是,如果从表达式(静态)调用
f
,则
Base
Derived
中名为
f
的方法不会同时考虑重载解析键入
Derived
,这一次是因为基类中的方法被
f
的声明隐藏在
Derived
中,因此它们不可用于此类调用。我认为可以通过使用base::f;
声明
来避免这种隐藏,它“提升”方法
Base::f
转化为
派生的
,就好像它们也在那里声明一样(但我承认我不知道这种机制的细节;我假设提升将是具有相同参数类型的虚拟基方法的重写,但这没有什么区别,因为提升引用基类中的实现。)

将pb更改为
派生*
并观察将发生什么。@dlf:编译器也会发出警告:-)这个标题不是很有用。想象一下,如果你在搜索结果中看到它,你会怎么想。实际上,它必须是这样的——你可能没有声明实际派生虚拟函数的源代码,事实上,重写函数可能还没有编写,所以(a)你无论如何也无法得到它的默认值,以及(b)即使可以,您的默认值在运行时动态更改为您永远无法测试的值也可能会让人大吃一惊。--顺便说一句,对于您从我这里引用的文本,我要改进的一点是,说“名称查找”比说“重载解析”更正确,但分析是正确的,结果是相同的。