我在一次采访中被问到这个问题。我无法在那里回答这个问题。我现在也无法理解为什么输出是这样的。 这是代码:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void fun ( int x = 0)
{
cout << "Base::fun(), x = " << x << endl;
}
};
class Derived : public Base
{
public:
virtual void fun ( float x = 10.0 )
{
cout << "Derived::fun(), x = " << x << endl;
}
};
int main()
{
Derived d1;
Base *bp = &d1;
bp->fun();
d1.fun();
d1.fun(1.2);
return 0;
}
以上代码的输出为:
Base::fun(), x = 0
Derived::fun(), x = 10
Derived::fun(), x = 1.2
问题是: 在第一种情况下,我们说 fun() 函数都被重载了(并且没有被覆盖,因为它们的声明不同)并且调用了基础 fun() ,但是 fun() 的这些声明不可能被重载(因为它们的区别仅在于声明是否包含默认参数)
void fun(int x = 0)
void fun(float x = 10.0)
这些函数不可能重载。
以上两种情况似乎都存在矛盾。
解释情况的任何相关文章/链接都会非常有帮助。
最佳答案
在 C++ 中,对于覆盖基类函数的成员函数,参数类型必须与基类函数的参数类型完全匹配。由于基类函数采用 int
而派生类的函数采用 float
,因此它不被视为重写。您可以使用 override
关键字看到这一点:
class Base
{
public:
virtual void fun ( int x = 0)
{
cout << "Base::fun(), x = " << x << endl;
}
};
class Derived : public Base
{
public:
virtual void fun ( float x = 10.0 ) override // Doesn't compile!
{
cout << "Derived::fun(), x = " << x << endl;
}
};
您的代码中发生的情况是,C++ 将您的函数视为重载(另一个同名函数),而不是覆盖。让我们看一下这段代码:
Derived d1;
Base *bp = &d1;
bp->fun();
这里,由于 bp->fun()
行使用了通过基类指针的调用,C++ 在 Base
中查找要调用的函数。它找到 Base::fun(int)
。现在,由于该函数被标记为 virtual
,它将调用 Base::fun(int)
除非有什么东西覆盖了它。但是由于没有覆盖,Base::fun(int)
最终被调用。
那么后面这两行呢?
d1.fun();
d1.fun(1.2);
在这里,由于您在 Derived
静态类型的对象上调用这些函数,C++ 会尝试在 Derived
中找到名为 fun
的函数> 类。它会找到您的新函数 Derived::fun(float)
,并且由于 C++ 在类中查找名称的方式,它不会在基类中查找 Base::fun(int )
。因此,这两个调用都被视为对 Derived::fun(float)
的调用,因此在没有提供参数时调用哪个函数没有歧义。编译器甚至从不查看 Base
类型,因为没有必要。
总结一下:
- 您引入了重载,而不是覆盖。使用 override 关键字可以帮助您在将来诊断此类问题。
- 通过基指针调用
fun
寻找一个名为fun
的函数接受一个int
,因为基指针的fun
函数接受一个int
。这会在Base
中找到版本,因为没有 oerride。 - 通过派生对象调用
fun
查找从Derived
开始的名为fun
的函数,它会找到您的覆盖。
关于c++ - 虚函数重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42816834/