调用虚函数时的奇怪行为

Strange behaviour when calling virtual functions

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

此代码:

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

编译

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

隐藏同名(但签名不同)的基本方法。

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

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

Foo 中有两个 foo 的重载,一个使用 double,另一个使用 int.

Bar 中有一个 foo 的重载,那个重载 double。此重载隐藏了基础 classes 中所有具有相同名称的函数。这叫做名字隐藏.

一个解决方法是使用using declarationFoo派生的范围内从基础class带来其他foo重载class:

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

这是因为名称隐藏。

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

因此,当指针的静态类型为 Bar 时,编译器 Bar 中找到采用 [=16] 的版本=], 所以它隐式转换 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; }
};