定义适当的减法运算符

发布于 2024-07-25 19:07:22 字数 955 浏览 2 评论 0原文

我为数学对象编写了一个抽象类,并定义了所有运算符。 在使用它时,我发现:

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);

我立即在 这是我讨厌的,并且用“静态”不必要的函数污染了命名空间。

在 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 关键字的方法吗?

同样的问题也适用于除法,因为它也遇到同样的问题。

I wrote an abstraction class for a math object, and defined all of the operators. While using it, I came across:

Fixed f1 = 5.0f - f3;

I have only two subtraction operators defined:

inline const Fixed operator - () const;
inline const Fixed operator - (float f) const;

I get what is wrong here - addition is swappable (1 + 2 == 2 + 1) while subtraction is not (same goes for multiplication and division).
I immediately wrote a function outside my class like this:

static inline const Fixed operator - (float f, const Fixed &fp);

But then I realized this cannot be done, because to do that I would have to touch the class's privates, which results to using the keyword friend which I loath, as well as polluting the namespace with a 'static' unnecessary function.

Moving the function inside the class definition yields this error in 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

Doing as GCC suggested, and making it a non-static function results the following error:

error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument

Why can't I define the same operator inside the class definition? if there's no way to do it, is there anyway else not using the friend keyword?

Same question goes for division, as it suffers from the same problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

把时间冻结 2024-08-01 19:07:22

如果您需要确保好友功能可以正常使用:

http://www.gotw.ca/gotw /084.htm

哪些操作需要访问
否则我们将拥有内部数据
通过友谊给予? 这些应该
一般都是会员。 (有一些
罕见的例外情况,例如操作
需要在左手进行转换
参数和一些像运算符<<()
其签名不允许 *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+...
}

或者只是固定(lhs) - rhs(如果您有显式float 构造函数)。 这些可能会或可能不会像您的朋友实施那样有效。

不幸的是,该语言不会竭尽全力去适应那些碰巧讨厌其关键字之一的人,因此运算符不能是静态成员函数并以这种方式获得友谊的效果;-p

If you need reassuring that friend functions can be OK:

http://www.gotw.ca/gotw/084.htm

Which operations need access to
internal data we would otherwise have
to grant via friendship? These should
normally be members. (There are some
rare exceptions such as operations
needing conversions on their left-hand
arguments and some like operator<<()
whose signatures don't allow the *this
reference to be their first
parameters; even these can normally be
nonfriends implemented in terms of
(possibly virtual) members, but
sometimes doing that is merely an
exercise in contortionism and they're
best and naturally expressed as
friends.)

You are in the "operations needing conversions on the left-hand arguments" camp. If you don't want a friend, and assuming you have a non-explicit float constructor for Fixed, you can implement it as:

static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) {
    return lhs.minus(rhs);
}

then implement minus as a public member function, that most users won't bother with because they prefer the operator.

I assume if you have operator-(float) then you have operator+(float), so if you don't have the conversion operator, you could go with:

static inline Fixed operator-(float lhs, const Fixed &rhs) {
    return (-rhs) + lhs;
    // return (-rhs) -(-lhs); if no operator+...
}

Or just Fixed(lhs) - rhs if you have an explicit float constructor. Those may or may not be as efficient as your friend implementation.

Unfortunately the language is not going to bend over backwards to accommodate those who happen to loathe one of its keywords, so operators can't be static member functions and get the effects of friendship that way ;-p

留一抹残留的笑 2024-08-01 19:07:22
  1. “这就是朋友的用途......”
  2. 您可以在 float 和您的类型之间添加隐式转换(例如,使用接受 float 的构造函数) ...但我确实认为使用朋友更好。
  1. "That's what friends are for..."
  2. You could add an implicit conversion between float and your type (e.g. with a constructor accepting float)... but I do think using a friend is better.
赠我空喜 2024-08-01 19:07:22

当你定义这样的东西时,

inline const Fixed operator - (float f) const;

你是在说我希望这个运算符(你在类内部)对特定类型进行操作,例如这里的 float 。

而友元二元运算符则表示两种类型之间的运算。

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.
}

对于友元操作员,您可以将自己的班级放在操作员的任一侧。

When you define something like this,

inline const Fixed operator - (float f) const;

you are saying that I want this operator(you are inside the class) to operate on a specific type, float here for example.

Whereas a friend binary operator, means an operation between two types.

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.
}

with friend operators you can have your class on either side of the operator it self.

我只土不豪 2024-08-01 19:07:22

一般来说,用于算术运算的自由函数运算符比实现成员函数更好。 主要原因是你现在面临的问题。 编译器会对左侧和右侧进行不同的处理。 请注意,虽然严格的 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 - FixFixed - doubledouble - Fixed。 编译器将找到 free 函数并将双精度数隐式转换(在示例中通过 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 );
}

In general, free function operators for arithmetic operations are better than implementing member functions. The main reason is the problem you are facing now. The compiler will treat the left and right sides differently. Note that while strict OO followers will consider only those methods inside the class curly braces part of its interface, but it has been argued by experts that not to be the case in C++.

If the free function operator requires access to private members, make the operator friend. After all if it is provided in the same header file (following Sutter's rationale above) then it is part of the class.

If you really want to avoid it and don't mind making your code less idiomatic (and thus less maintainable) you can provide a public method that does the real work and dispatch to that method from the operator.

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 );
}

In the code above, you can substract Fixed - Fixed, Fixed - double, double - Fixed. The compiler will find the free function and implicitly convert (in the example through the double constructor) the doubles into Fixed objects.

While this is unidiomatic for arithmetic operators, it is close to the idiomatic way of proving a polymorphic dump operator. So while not being the most natural solution it won't be the most surprising code around either

// 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 );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文