我有以下问题:
假设基类A使用方法:
A& operator+(A& a) {...}
我还有一个派生类B,它重载(或者至少应该这样)这个方法:
A& operator+(B& b) {...}
问题是,如果我想打电话: b + a(其中b是B类型,A类型是A)我得到编译错误。 (错误C2679:二进制'+':找不到带有'A'类型右手操作数的运算符(或者没有可接受的转换)。
不应该调用基类方法吗? (看起来它覆盖了方法..) 如果没有,为什么?有没有办法解决这个问题(不要告诉我使用A& amp来重载B中的方法)
抱歉,我不提供格式化文本中的示例,但我不知道如何格式化。
提前致谢!
PS Im使用Visual Studio 2010测试版。
答案 0 :(得分:3)
该问题称为隐藏 - 派生类中的成员函数隐藏基类中具有相同名称的函数。在这种情况下,您无法访问A :: operator +(A&),因为它被B :: operator +隐藏。解决这个问题的方法是定义B :: operator +(A&),并可能让它调用基类函数。
修改:section in the C++ FAQ Lite有关于此问题的详细信息,并提供了另一种可能的解决方案,即using
关键字。
答案 1 :(得分:2)
问题在于您正在定义成员运算符,因此当调用b + a
时,它会生成b.operator+( a )
,这不存在。
接受的做法是定义自由运算符,它们自己会在参数上调用[virtual]成员。
class base
{
public:
virtual ~base();
virtual void print( std::ostream& ) const;
};
std::ostream& operator<<( std::ostream& out, const base& b )
{
b.print( out ); return out;
}
这对数学运算不起作用,因为你想通过[const]值而不是引用返回,即避免像a + b = c;
这样的废话。
例如,定义了实数和复数的加法,但结果会产生复数,因此您无法从complex
派生real
。另一种方式 - 也许吧。但是你仍然想要定义精确的操作界面:
const real operator+( const real&, const real& );
const complex operator+( const complex&, const complex& );
希望这能让你重新思考你的设计:)
答案 2 :(得分:2)
不,它不会调用基类函数。 B类有一个operator+
,它没有采用正确的参数,故事结束。
您可以将operator+
定义为自由函数,而不是在任何类中。也许是朋友,如果需要访问私人数据:
A operator+(const A &lhs, const A &rhs) { ... }
B operator+(const B &lhs, const B &rhs) { ... }
然后b + a将调用第一个运算符,a + b也将调用。 b + b会拨打第二个。
或者,您可以通过将其放在B类中来“取消隐藏”基类实现:
using A::operator+;
但是,最好不要这样做。大多数运算符作为自由函数更好地工作,因为这样就可以在两个操作数上实现自动转换。 C ++从不在成员函数调用的LHS上执行转换。
顺便说一句,运算符+几乎肯定应该按值返回,而不是通过引用返回,因为一旦函数返回,自动(堆栈)变量就不再存在了。因此调用者需要传递结果的副本,而不是对它的引用。出于这个原因,operator +和inheritance并不是一个很好的组合,尽管只要调用者知道他们在做什么就可以工作。
答案 3 :(得分:0)
我想到了一些事情。首先,您通常希望使运算符+“虚拟”。然后,派生的运算符+对B的引用将由于协方差而被覆盖,而不是隐藏基类实现,这就是这里发生的事情。
那就是说,我怀疑(但不能说没有编译测试项目),这实际上可以解决你的问题。那是因为二元运算符的标准答案是使用在类上带两个参数的静态方法。 C ++ STL广泛使用这种技术,我不知道尝试将二元运算符实现为实例方法(虚拟或非虚拟)的原因。这太混乱了,没有真正的好处。