我在接受采访时被问到这个问题。我无法在那里回答这个问题。我现在也无法得到它,为什么输出是这样的。 这是代码:
#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)
这些功能无法过载。
上述两种情况似乎都存在矛盾。
任何解释这种情况的相关文章/链接都会非常有用。
答案 0 :(得分:13)
在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 ++会尝试在fun
类中查找名为Derived
的函数。它找到了你的新函数Derived::fun(float)
,并且由于C ++在类中进行名称查找的方式,它不会在基类中查找Base::fun(int)
。因此,这两个调用都被视为对Derived::fun(float)
的调用,因此没有关于在没有参数的情况下调用哪个函数的歧义。编译器甚至从未查看Base
类型,因为没有必要。
所以,总结一下:
fun
会查找名为fun
的函数,该函数会引入int
,因为基指针的fun
函数会接收int
。找到Base
中的版本,因为没有oerride。fun
从fun
开始查找名为Derived
的函数,并找到您的覆盖。