【问题标题】:Overloading of virtual functions虚函数重载
【发布时间】:2017-08-06 14:37:41
【问题描述】:

我在一次采访中被问到这个问题。我无法在那里回答这个问题。我现在也无法得到它,至于为什么输出是这样的。 代码如下:

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

这些函数不可能重载。

上述两种情况似乎存在矛盾。

任何解释这种情况的相关文章/链接都会非常有帮助。

【问题讨论】:

  • 您期望输出是什么以及为什么?
  • 在第一种情况下,由于运行时多态性,输出应该是 Derived::fun(), x = 10.0。第二种和第三种情况,你如何决定输出?

标签: c++ inheritance overriding overloading


【解决方案1】:

在 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-&gt;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 的函数,并找到您的覆盖。

【讨论】:

  • 第一种情况,为什么没有运行时多态性?
  • @YamanSingla 刚刚更新了答案以解释发生了什么。
  • 非常感谢@templatetypedef 的帮助。我现在明白到底发生了什么!
  • 在第二种和第三种情况下,函数重载是不可能的(因为函数定义仅在默认参数是否存在方面有所不同),但是正如您在回答中所说的那样,在第一种情况下,函数被重载(而不是被覆盖)。这不是矛盾吗?
  • @YamanSingla 哦,我想我明白你在说什么了。 C++ 在此处进行名称查找的方式列出了这一点。首先,它查看接收器对象的静态类型以确定从哪里开始查找。 (这里是Derived)。然后它会查看您正在调用的函数的名称(此处为fun)并查找匹配项。因为它在Derived 中找到了一个名为fun 的函数,所以它停止寻找其他匹配项。 (在 C++ 中有一个怪癖,如果在派生类中找到名称,则永远不会搜索基类的重载)。因此,它会找到 Derived::fun(float) 并使用它。
猜你喜欢
  • 2023-01-07
  • 2017-08-12
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 2012-02-07
相关资源
最近更新 更多