我为数学对象编写了一个抽象类,并定义了所有运算符。使用它时,我遇到了:
Fixed f1 = 5.0f - f3;
我只定义了两个减法运算符:
inline const Fixed operator - () const;
inline const Fixed operator - (float f) const;
我在这里得到了什么错误 - 加法是可交换的(1 + 2 == 2 + 1)而减法不是(乘法和除法相同)。 我立即在我的课外写了一个函数,如下所示:
static inline const Fixed operator - (float f, const Fixed &fp);
但后来我意识到这不可能做到,因为为了做到这一点,我将不得不触及类的私有,这导致使用我厌恶的关键字friend
,以及用'静态污染命名空间'不必要的功能。
在类定义中移动函数会在gcc-4.3中产生此错误:
error: ‘static const Fixed Fixed::operator-(float, const Fixed&)’ must be either a non-static member function or a non-member function
按照GCC建议,并使其成为非静态函数会导致以下错误:
error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument
为什么我不能在类定义中定义相同的运算符?如果无法做到这一点,那么其他方面是否还没有使用friend
关键字?
同样的问题适用于分裂,因为它遇到了同样的问题。
答案 0 :(得分:3)
如果您需要放心,朋友的功能可以正常:
http://www.gotw.ca/gotw/084.htm
需要访问哪些操作 否则我们会有内部数据 通过友谊授予?这些应该 通常是会员。 (有一些 罕见的例外,例如操作 需要左手转换 参数和一些像运算符<<() 其签名不允许* this 参考是他们的第一个 参数;即使这些通常也可以 非友好的实施方式 (可能是虚拟的)成员,但是 有时这样做只是一个 在扭曲中锻炼,他们是 最好的,自然地表达为 朋友。)
您正处于“需要在左侧参数上进行转换的操作”阵营中。如果您不想要朋友,并且假设您有float
的非显式Fixed
构造函数,则可以将其实现为:
static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) {
return lhs.minus(rhs);
}
然后将minus
实现为公共成员函数,大多数用户都不会因为喜欢运营商而烦恼。
我假设你有operator-(float)
,那么你有operator+(float)
,所以如果你没有转换运营商,你可以选择:
static inline Fixed operator-(float lhs, const Fixed &rhs) {
return (-rhs) + lhs;
// return (-rhs) -(-lhs); if no operator+...
}
如果您有明确的Fixed(lhs) - rhs
构造函数,则只需float
。那些可能会或可能不会像您的朋友实施那样有效。
不幸的是,语言不会向后倾斜,以适应那些碰巧厌恶某个关键字的人,因此操作符不能成为静态成员函数并以这种方式获得友谊的效果;-p
答案 1 :(得分:1)
float
和您的类型之间添加隐式转换(例如,使用构造函数接受float
)...但我确实认为使用friend
更好。答案 2 :(得分:0)
当你定义这样的东西时,
inline const Fixed operator - (float f) const;
你说我希望这个操作符(你在类中)对特定类型进行操作,例如在这里浮动。
而友元二元运算符意味着两种类型之间的操作。
class Fixed
{
inline friend const Fixed operator-(const Fixed& first, const float& second);
};
inline const Fixed operator-(const Fixed& first, const float& second)
{
// Your definition here.
}
与朋友操作员一起,您可以将自己的班级放在操作员的任何一侧。
答案 3 :(得分:0)
通常,算术运算的自由函数运算符优于实现成员函数。主要原因是你现在面临的问题。编译器将以不同方式处理左侧和右侧。请注意,虽然严格的OO关注者将只考虑其类接口的类花括号内部的那些方法,但专家已经argued而不是C ++中的情况。
如果自由功能操作员需要访问私人会员,请成为操作员朋友。毕竟如果它是在同一个头文件中提供的(遵循上面的Sutter的基本原理)那么它就是该类的一部分。
如果你真的想避免使用它并且不介意使你的代码不那么惯用(因此维护性较差),你可以提供一个公共方法来完成实际工作并从操作员发送到该方法。
class Fixed {
private:
Fixed();
Fixed( double d ); // implicit conversion to Fixed from double
Fixed substract( Fixed const & rhs ) const;
// ...
};
Fixed operator-( Fixed const & lhs, Fixed const & rhs )
{
return lhs.substract( rhs );
}
在上面的代码中,您可以减去Fixed - Fixed
,Fixed - double
,double - Fixed
。编译器将找到自由函数并隐式转换(在示例中通过double
构造函数)双精度到Fixed
个对象。
虽然这对于算术运算符来说是单一的,但它接近于证明多态转储运算符的惯用方法。因此,虽然不是最自然的解决方案,但它不会是最令人惊讶的代码
// idiomatic polymorphic dump operator
class Base {
public:
virtual std::ostream& dump( std::ostream & ) const;
};
std::ostream& operator<<( std::ostream& o, Base const & d )
{
return d.dump( o );
}