[英]Defining a proper subtraction operator
我为数学对象编写了一个抽象类,并定义了所有运算符。 使用时,我遇到了:
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
关键字的东西?
同样的问题也适用于除法,因为它遭受了同样的问题。
如果您需要确保朋友功能可以正常运行:
http://www.gotw.ca/gotw/084.htm
哪些操作需要访问我们否则必须通过友谊授予的内部数据? 这些通常应该是成员。 (有一些罕见的例外,例如需要在其左手参数上进行转换的操作,以及一些类似operator <<()的操作,其签名不允许* this引用为它们的第一个参数;即使这些通常可以用术语实现,也可以是非友善的(可能是虚拟的)成员,但有时这样做只是扭曲主义的一种练习,他们最好且自然地表现为朋友。)
您正处于“需要在左侧参数上进行转换的操作”阵营中。 如果您不想要朋友,并且假设您为Fixed
拥有一个非显式的float
构造函数,则可以将其实现为:
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
float
和您的类型之间添加隐式转换(例如,使用接受float
的构造函数)...但是我确实认为使用friend
会更好。 当您定义这样的内容时,
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.
}
与朋友接线员一起,您可以将自己的班级放在接线员的任一侧。
通常,用于算术运算的自由函数运算符要好于实现成员函数。 主要原因是您现在面临的问题。 编译器将左右区别对待。 请注意,虽然严格的OO追随者只考虑它的接口的类的花括号里面的一部分的方法,但它已被认为专家是不是在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
。 编译器将找到free函数,并将double
隐式转换(在示例中通过double
构造函数),将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 );
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.