调用虚函数时的奇怪行为
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 declaration从Foo
派生的范围内从基础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; }
};
我不明白这段代码有什么问题。这看起来像一个不可思议的陷阱!
此代码:
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 declaration从Foo
派生的范围内从基础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; }
};