采访中有人问我这个问题。我在那里无法回答。关于输出为何如此,我现在也无法得到它。
这是代码:
#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++会尝试在fun
类中找到一个称为Derived
的函数。它会找到您的新函数Derived::fun(float)
,并且由于C++在类中进行名称查找的方式,因此它不会在基类中查找Base::fun(int)
。因此,这两个调用都被视为对Derived::fun(float)
的调用,因此在不提供参数的情况下调用哪个函数没有任何歧义。编译器甚至从未查看过Base
类型,因为没有必要。因此,总结一下:
fun
会寻找一个接受fun
的名为int
的函数,因为基本指针的fun
函数需要一个int
。这样就可以找到Base
中的版本,因为没有oerride。 fun
会查找一个从fun
开始的名为Derived
的函数,并会找到您的替代项。 关于c++ - 虚拟功能的重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42816834/