【问题标题】:Strange behaviour when calling virtual functions调用虚函数时的奇怪行为
【发布时间】:2015-06-10 08:51:13
【问题描述】:

我不明白这段代码有什么问题。它看起来像一个不可思议的陷阱!

这段代码:

class Foo
{
  public:
      virtual double foo(double x) const = 0;
              double foo(int x) const { return (double)(x + x); }
};

class Bar : public Foo
{
    public:
        virtual double foo(double x) const { return x * x; }
};

int main()
{
    Bar* b = new Bar;
    Foo* f = b;
    std::cout << b->foo(3) << " " << f->foo(3) << std::endl;
    std::cout << b->foo(5.0) << " " << f->foo(5.0) << std::endl;
    return 0;
}

打印以下输出:

9 6
25 25

我推断当指针的类型为Bar* 时,Bar::foo(double) const 是通过隐式转换调用的。但是为什么会在没有任何警告的情况下发生这样的事情?

我使用 GCC 4.7.2。我用g++ -Wall foobar.cpp -o foobar.exe编译

【问题讨论】:

  • 我认为如果你选择第二个数字而不是 2 会更好。因为 2*2=4 和 2+2=4。
  • 我很好奇,如果foo(int)的返回值也是int,你有同样的问题吗? @nabroyan 确实,使用相同的值(但类型不同)会更好:33.0
  • 你是对的。我换成了5.0
  • @Kryptos:是的,同样的行为。

标签: c++ virtual


【解决方案1】:

这是由于名称隐藏。

当您在Bar 中声明一个名为foo 的函数时,您将隐藏Foo 中的所有同名声明。

因此,当指针的静态类型为Bar 时,编译器Bar 中找到带有double 的版本,因此它隐式转换int满足这一点。

如果您希望Foo 中的int 版本可见,请添加using 声明:

class Bar : public Foo
{
    public:
        using Foo::foo;
//      ^^ makes the versions in Foo visible
        virtual double foo(double x) const { return x * x; }
};

【讨论】:

    【解决方案2】:

    当类型为Bar* 时,只有一个版本的方法可见,即带有double 参数的版本。

    具有相同名称(但签名不同)的基本方法被隐藏。

    要使它们可用,您可以在派生类中使用using Foo::foo

    根据您的编译器,我认为您可能还会收到有关隐式转换的警告,或者您显然想要调用隐藏方法这一事实。

    【讨论】:

      【解决方案3】:

      Foo 中有两个foo 重载,一个采用double,另一个采用int

      Bar 中有一个foo 的重载,它采用double。此重载从基类中隐藏了所有具有相同名称的函数。这称为名称隐藏

      解决方法是使用 using 声明 将基类中的其他 foo 重载带入 Foo 派生类的范围内:

      class Bar : public Foo
      {
          public:
              using Foo::foo; 
              virtual double foo(double x) const { return x * x; }
      };
      

      【讨论】:

        猜你喜欢
        • 2015-01-27
        • 2015-11-02
        • 2015-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多