可能重复:
C++ overload resolution
我遇到了一个问题,在我的类重写了它的基类函数之后,所有函数的重载版本都被隐藏了。这是设计还是我做错了什么?
实施例
class foo
{
public:
foo(void);
~foo(void);
virtual void a(int);
virtual void a(double);
};
class bar : public foo
{
public:
bar(void);
~bar(void);
void a(int);
};
以下将给出编译错误,说明条中没有(双)函数。
main()
{
double i = 0.0;
bar b;
b.a(i);
}
答案 0 :(得分:67)
在课程栏中,添加
using foo::a;
这是C ++中常见的“问题”。一旦在类范围中找到名称匹配,它就不会进一步查看继承树的重载。通过指定'using'声明,您可以将'f'中的'a'的所有重载带入'bar'的范围。然后重载正常工作。
请记住,如果现有代码使用'foo'类,其含义可能会被其他重载更改。或者额外的重载可能会引入歧义,并且代码将无法编译。 James Hopkin的回答指出了这一点。
答案 1 :(得分:20)
这就是语言运作的方式。在使用关键字之前,如果您覆盖了一个重载函数,则必须将它们全部重载:
class bar : public foo
{
public:
bar(void);
~bar(void);
a(int);
a(double d) { foo::a(d); } // add this
}
这让很多人感到恼火,语言委员会添加了使用功能,但是一些旧习惯很难过;和habitués†有一个很好的争论。
正如James Hopkins指出的那样,通过添加使用,程序员表达了这样的意图:派生类将在没有警告的情况下将foo :: a()的任何未来覆盖添加到其列表中可接受的签名。
以下是他描述的一个例子:
#include <iostream>
class Base {
public:
virtual void f(double){ std::cout << "Base::Double!" << std::endl; }
// virtual void f(int) { std::cout << "Base::Int!" << std::endl; } // (1)
virtual ~Base() {}
};
class Derived : public Base {
public:
// using Base::f; // (2)
void f(double) { std::cout << "Derived::Double!" << std::endl; }
};
int main(int, char **) {
Derived d;
d.f(21);
return 0;
}
输出将是“Derived :: Double!”因为编译器会将整数参数提升为double。 g ++ 4.0.1 -Wall不会警告此促销活动已经发生。
取消注释(1)以模拟对Base添加方法Base :: f(int)的未来更改。即使使用-Wall,代码也会在没有任何警告的情况下编译,并且“Derived :: Double!”仍然是输出。
现在取消注释(2)模拟Derived程序员决定包含所有Base :: f签名。代码编译(没有警告),但输出现在是“Base :: Int!”。
-
†我想不出一个英文单词“有习惯的人”和“上瘾”太强了。
答案 2 :(得分:11)
这是设计的。过载分辨率仅限于单个范围。当附加函数被添加到基类或命名空间范围时,它可以防止一些令人讨厌的有效代码更改意义。