Team LiB
Previous Section Next Section

14.3. Arithmetic and Relational Operators

14.3. 算术操作符和关系操作符

Ordinarily, we define the arithmetic and relational operators as nonmember functions, as we do here with our Sales_item addition operator:

一般而言,将算术和关系操作符定义为非成员函数,像下面给出的 Sales_item 加法操作符一样:

     // assumes that both objects refer to the same isbn
     Sales_item
     operator+(const Sales_item& lhs, const Sales_item& rhs)
     {
         Sales_item ret(lhs);  // copy lhs into a local object that we'll return
         ret += rhs;           // add in the contents of rhs
         return ret; // return ret by value
     }

The addition operator doesn't change the state of either operand; the operands are references to const objects. Instead, it generates and returns a new Sales_item object, which is initialized as a copy of lhs. We use the Sales_item compound-assignment operator to add in the value of rhs.

加法操作符并不改变操作符的状态,操作符是对 const 对象的引用;相反,它产生并返回一个新的 Sales_item 对象,该对象初始化为 lhs 的副本。我们使用 Sales_item 的复合赋值操作符来加入 rhs 的值。

Note that to be consistent with the built-in operator, addition returns an rvalue, not a reference.

注意,为了与内置操作符保持一致,加法返回一个右值,而不是一个引用。



An arithmetic operator usually generates a new value that is the result of a computation on its two operands. That value is distinct from either operand and is calculated in a local variable. It would be a run-time error to return a reference to that variable.

算术操作符通常产生一个新值,该值是两个操作数的计算结果,它不同于任一操作数且在一个局部变量中计算,返回对那个变量的引用是一个运行时错误。

Classes that define both an arithmetic operator and the related compound assignment ordinarily ought to implement the arithmetic operator by using the compound assignment.

既定义了算术操作符又定义了相关复合赋值操作符的类,一般应使用复合赋值实现算术操作符。



It is simpler and more efficient to implement the arithmetic operator (e.g., +) in terms of the compound-assignment operator (e.g., +=) rather than the other way around. As an example, consider our Sales_item operators. If we implemented += by calling +, then += would needlessly create and destroy a temporary to hold the result from +.

根据复合赋值操作符(如 +=)来实现算术操作符(如 +),比其他方式更简单且更有效。例如,我们的 Sales_item 操作符。如果我们调用 += 来实现 +,则可以不必创建和撤销一个临时量来保存 + 的结果。

Exercises Section 14.3

Exercise 14.12:

Write the Sales_item operators so that + does the actual addition and += calls +. Discuss the disadvantages of this approach compared to the way the operators were implemented in this section.

编写 Sales_item 操作符,用 + 进行实际加法,而 += 调用 +。与本节中操作符的实现方法相比较,讨论这个方法的缺点。

Exercise 14.13:

Which other arithmetic operators, if any, do you think Sales_item ought to support? Define those that you think the class should include.

如果有,你认为 Sales_item 还应该支持哪些其他算术操作符?定义你认为该类应包含的哪些。


14.3.1. Equality Operators

14.3.1. 相等操作符

Ordinarily, classes in C++ use the equality operator to mean that the objects are equivalent. That is, they usually compare every data member and treat two objects as equal if and only if all corresponding members are the same. In line with this design philosophy, our Sales_item equality operator should compare the isbn as well as the sales figures:

通常,C++ 中的类使用相等操作符表示对象是等价的。即,它们通常比较每个数据成员,如果所有对应成员都相同,则认为两个对象相等。与这一设计原则一致,Sales_item 的相等操作符应比较 isbn 以及销售数据:

     inline bool
     operator==(const Sales_item &lhs, const Sales_item &rhs)
     {
         // must be made a friend of Sales_item
         return lhs.units_sold == rhs.units_sold &&
                lhs.revenue == rhs.revenue &&
            lhs.same_isbn(rhs);
     }
     inline bool
     operator!=(const Sales_item &lhs, const Sales_item &rhs)
     {
         return !(lhs == rhs); // != defined in terms of operator==
     }

The definition of these functions is trivial. More important are the design principles that these functions embody:

这些函数的定义并不重要,重要的是这些函数所包含的设计原则:

  • If a class defines the == operator, it defines it to mean that two objects contain the same data.

    如果类定义了 == 操作符,该操作符的含义是两个对象包含同样的数据。

  • If a class has an operation to determine whether two objects of the type are equal, it is usually right to define that function as operator== rather than inventing a named operation. Users will expect to be able to compare objects using ==, and doing so is easier than remembering a new name.

    如果类具有一个操作,能确定该类型的两个对象是否相等,通常将该函数定义为 operator== 而不是创造命名函数。用户将习惯于用 == 来比较对象,而且这样做比记住新名字更容易。

  • If a class defines operator==, it should also define operator!=. Users will expect that if they can use one operator, then the other will also exist.

    如果类定义了 operator==,它也应该定义 operator!=。用户会期待如果可以用某个操作符,则另一个也存在。

  • The equality and inequality operators should almost always be defined in terms of each other. One operator should do the real work to compare objects. The other should call the one that does the real work.

    相等和不操作符一般应该相互联系起来定义,让一个操作符完成比较对象的实际工作,而另一个操作符只是调用前者。

Classes that define operator== are easier to use with the standard library. Some algorithms, such as find, use the == operator by default. If a class defines ==, then these algorithms can be used on that class type without any specialization.

定义了 operator== 的类更容易与标准库一起使用。有些算法,如 find,默认使用 == 操作符,如果类定义了 ==,则这些算法可以无须任何特殊处理而用于该类类型。



14.3.2. Relational Operators

14.3.2. 关系操作符

Classes for which the equality operator is defined also often have relational operators. In particular, because the associative containers and some of the algorithms use the less-than operator, it can be quite useful to define an operator<.

定义了相等操作符的类一般也具有关系操作符。尤其是,因为关联容器和某些算法使用小于操作符,所以定义 operator< 可能相当有用。

Although we might think our Sales_item class should support the relational operators, it turns out that it probably should not. The reasons are somewhat subtle and deserve understanding.

我们也许认为 Sales_item 类应该支持关系操作符,但恰恰相反,它很可能不应该支持关系操作符,原因有些微妙,值得了解。

As we'll see in Chapter 15, we might want to use an associative container to hold Sales_item transactions. When we put objects into the container, we'd want them ordered by ISBN, and wouldn't care whether the sales data in two records were different.

正如第十五章将要介绍的,我们可能想要使用关联容器来保存 Sales_item 事务。将对象放在容器中时,我们希望它们按 ISBN 排序,而不会关心两个记录中的销售数据是否不同。

However, if we were to define operator< as comparison on isbn, that definition would be incompatible with the obvious definition of ==. If we had two transactions for the same ISBN, neither record would be less than the other. Yet, if the sales figures in those objects were different, then these objects would be !=. Ordinarily, if we have two objects, neither of which is less than the other, then we expect that those objects are equal.

但是,如果将 operator< 定义为对 isbn 的比较,该定义将与前面 == 的定义不相容。如果有两个针对同一 ISBN 的事务,其中任意一个都不会小于另一个,然而,如果这两个对象中的销售数据不同,则它们就不相等。但是,一般说来,如果有两个对象,其中任意一个都不小于另一个,则认为它们相等。

Because the logical definition of < is inconsistent with the logical definition of ==, it is better not to define < at all. We'll see in Chapter 15 how to use a separate named function to compare Sales_items when we want to store them in an associative container.

因为 < 的逻辑定义与 == 的逻辑定义不一致,所以根本不定义 < 会更好。第十五章将会介绍想要将 Sales_items 对象存储到关联容器中时,怎样使用单独的命名函数来比较 Sales_items 对象。

The associative containers, as well as some of the algorithms, use the < operator by default. Ordinarily, the relational operators, like the equality operators, should be defined as nonmember functions.

关联容器以及某些算法,使用默认 < 操作符。一般而言,关系操作符,诸如相等操作符,应定义为非成员函数。



Team LiB
Previous Section Next Section