繁体   English   中英

定义适当的减法运算符

[英]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

  1. “这就是朋友的作用...”
  2. 您可以在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 - FixedFixed - doubledouble - 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM