c++ - 虚函数重载

标签 c++ inheritance overriding overloading

我在一次采访中被问到这个问题。我无法在那里回答这个问题。我现在也无法理解为什么输出是这样的。 这是代码:

#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/

相关文章:

c++ - 在UE4中,为什么要重写BeginPlay,为什么要在重写的BeginPlay中调用Super::BeginPlay?

c++ - 使用第三方库的菱形继承(钻石问题)问题

c++ - 如何在派生类中初始化静态成员?

c++ - 令人困惑的继承示例。构造函数被重写,但函数没有。为什么?

c++ - 虚函数覆盖和隐藏

c++ - 抽象类和继承的问题

c++ - const char 数组模板 vs char const* 函数重载

c++ - 在 OpenGL 中绘制扭曲平面的正确方法是什么?

c++ - 为命名空间中的类重载运算符 << 时发出警告

Python在继承时使用带有super的类属性