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)即使可以,您的默认值在运行时动态更改为您永远无法测试的值也可能会让人大吃一惊。--顺便说一句,对于您从我这里引用的文本,我要改进的一点是,说“名称查找”比说“重载解析”更正确,但分析是正确的,结果是相同的。