采访中有人问我这个问题。我在那里无法回答。关于输出为何如此,我现在也无法得到它。
这是代码:

#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类型,因为没有必要。

因此,总结一下:
  • 您引入了重载,而不是覆盖。使用override关键字将有助于您将来诊断此类问题。
  • 通过基本指针调用fun会寻找一个接受fun的名为int的函数,因为基本指针的fun函数需要一个int。这样就可以找到Base中的版本,因为没有oerride。
  • 通过派生对象调用fun会查找一个从fun开始的名为Derived的函数,并会找到您的替代项。
  • 关于c++ - 虚拟功能的重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42816834/

    10-11 22:56
    查看更多