Common operators to overload
Most of the work in overloading operators is boiler-plate code. That is little wonder, since operators was merely syntactic sugar, their actual work could being done by (and often is Forwar Ded to) plain functions. But it's important that's get this boiler-plate code right. If you fail, either your operator ' s code won ' t compile or your users ' code won ' t compile or your users ' code would behave s urprisingly.
Assignment Operator
There's a lot to being said about assignment. However, most of it have already been said in GMan ' s famous copy-and-swap FAQs, so I'll skip most of it here, only listing T He perfect assignment operator for reference:
X& X::operator=(X rhs) //参数位值传递{ swap(rhs); return *this;}
Bitshift Operators (used for Stream I/O)
The bitshift operators <<
and >>
, although still used in Hardware interfacing for the bit-manipulation functions they inherit from C, has become more prevalent as overloaded stre am input and output operators in most applications. For guidance overloading as bit-manipulation operators, see the sections below on Binary arithmetic operators. For implementing your own custom format and parsing logic when your object was used with IOStreams, continue.
The stream operators, among the most commonly overloaded operators, is binary infix operators for which the syntax spe Cifies no restriction on whether they should is members or non-members. Since They change their left argument (they alter the stream's state), they should, according to the rules of thumb, be IM Plemented as members of their left operand ' s type. However, their left operands is streams from the standard library, and while the most of the stream output and input operator s defined by the standard library is indeed defined as members of the stream classes, when you implement output and input Operations for your own types, you cannot change the standard library ' s stream types. That's why you need to implement these operators for your own types as non-member functions. The canonical forms of the These:
std::ostream& operator<<(std::ostream& os, const T& obj){ // write obj to stream return os;}std::istream& operator>>(std::istream& is, T& obj){ // read obj from stream if( /* no valid object of T found in stream */ ) is.setstate(std::ios::failbit); return is;}
When implementing operator>>
, manually setting the stream's state was only necessary when the reading itself succeeded, but the Result is a would be expected.
Function call operator
The function call operator, used to create function objects, also known as functors, must is defined as a member function, so it always has the implicit this
argument of member functions. Other than this it can is overloaded to take any number of additional arguments, including zero.
Throughout the C + + standard library, function objects is always copied. Your own function objects should therefore is cheap to copy. If a function object absolutely needs to use data which are expensive to copy, it's better to store that data elsewhere an D has the function object refer to it.
Comparison operators
The binary infix comparison operators should, according to the rules of thumb, be implemented as Non-member functions1. The unary prefix negation !
should (according to the same rules) is implemented as a member function. (but it's usually not a good idea to overload it.)
The standard library ' s algorithms (e.g. std::sort ()
) and types (e.g. std::map
) Would always have only expect operator<
to is present. However, the users of your type would expect all the other operators to being present , too, so if you define&nbs P operator<
, being sure to follow the third fundamental rule of operator overloading and also define all the OT Her Boolean comparison operators. The canonical-Implement them is this:
inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }inline bool operator> (const X& lhs, const X& rhs){return operator< (rhs,lhs);}inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}
The important thing to note this is, and only a these operators actually do anything, the others is just forwarding Their arguments to either of these and the actual work.
The syntax for overloading the remaining binary Boolean operators ( ||
, &&
) follows the rules of the comparison opera Tors. However, it's very unlikely that you would find a reasonable use case for THESE2.
1 As with all rules of thumb, sometimes there might is reasons to break this one, too. If So, does not forget this left-hand operand of the binary comparison operators, which for member functions would be , needs to be const
, too. So a comparison operator implemented as a member function would has the this signature:
bool operator<(const X& rhs) const { /* do actual comparison with *this */ }
(Note the At the const
end.)
2 It should is noted that the built-in version of and use ||
&&
shortcut semantics. While the user defined ones (because they is syntactic sugar for method calls) does not use shortcut semantics. User'll expect these operators to has shortcut semantics, and their code may depend on it, Therefore it's highly advis Ed never to define them.
Arithmetic operatorsunary arithmetic operators
The unary increment and decrement operators come in both prefix and postfix flavor. To tell one from the other, the Postfix variants take an additional dummy int argument. If you overload increment or decrement, being sure to always implement both prefix and postfix versions. Here is the canonical implementation of increment, decrement follows the same rules:
class X { X& operator++() { // do actual increment return *this; } X operator++(int) //后缀运算符,返回值为 值传递 { X tmp(*this); operator++(); return tmp; }};
Note that the Postfix variant was implemented in terms of prefix. Also Note that Postfix does an extra copy.2
Overloading unary minus and plus are not very common and probably best avoided. If needed, they should probably be overloaded as member functions.
2 Also Note the Postfix variant does more work and are therefore less efficient to use than the prefix variant. This was a good reason to generally prefer prefix increment over postfix increment. While compilers can usually optimize away the additional work of postfix increment for built-in types, they might ble to does the same for user-defined types (which could is something as innocently looking as a list iterator). Once you got used to does i++
, it becomes very hard-to-remember to does instead when was not of ++i
i
a built-in type ( Plus you ' d has to change code when changing a type), so it's better to make a habit of always using prefix increment, UN Less postfix is explicitly needed.
Binary arithmetic operators
For the binary arithmetic operators, does not forget to obey the third basic rule operator Overloading:if you provide +
, also provide +=
, if you provide -
, does not omit -=
, etc. Andrew Koenig is said to has been the first to observe, the compound assignment operators can be used as a base for T Heir Non-compound counterparts. That is, operator are +
implemented in terms +=
of, are implemented in terms of -
-=
etc.
According to We rules of thumb, and its +
companions should is non-members, while their compound assignment counterpa RTS ( +=
etc), changing their left argument, should is a member. Here +=
+
are the exemplary code for and, the other binary arithmetic operators should being implemented in the same By:
class X { X& operator+=(const X& rhs) { // actual addition of rhs to *this return *this; }};inline X operator+(X lhs, const X& rhs){ lhs += rhs; return lhs;}
operator+=
Returns its result per reference and while operator+
returns a copy of the its result. Of course, returning a reference is usually more efficient than returning a copy, but operator+
in the case of, there is no WA Y around the copying. When you write a + b
, you expect the result of a new value, which is why have to operator+
return a new value.3 Also note th At operator+
takes it left operand by copy rather than by const reference. The reason for the same as the reason giving for taking its operator=
argument per copy.
The bit manipulation operators should is implemented in the same as the ~
&
|
^
<<
>>
arithmetic Operators. However, (except for overloading and for <<
>>
output and input) there is very few reasonable use cases for Overloa Ding these.
3 Again, the lesson to being taken from the-is a += b
-is, in general, more efficient than and a + b
should be preferred If possible.
Array subscripting
The array subscript operator is a binary operator which must be implemented as a class member. It is used for container-like types this allow access to their data elements by a key. The canonical form of providing these is this:
class X { value_type& operator[](index_type idx); const value_type& operator[](index_type idx) const; // ...};
Unless you don't want users of your class to being able to change data elements returned by (in which case you operator[]
can OMI T the Non-const variant), you should always provide both variants of the operator.
If Value_type is known to refer to a built-in type, the const variant of the operator should return a copy instead of a CO NST Reference.
Operators for Pointer-like Types
For defining your own iterators or smart pointers, you had to overload the unary prefix dereference operator and *
th E binary infix pointer member access operator ->
:
class my_ptr { value_type& operator*(); const value_type& operator*() const; value_type* operator->(); const value_type* operator->() const;};
Note that these, too, would almost always need both a const and a non-const version. ->
value_type
class
for the operator must is of (or struct
or union
) type, otherwise their implementation results in a compile -time error.
The unary address-of operator should never be overloaded.
For see this operator->*()
question. It ' s rarely used and thus rarely ever overloaded. In fact, even iterators does not overload it.
---------------------------------------------------------------------------
-Excerpt from StackOverflow http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708
Common standard syntax for operators to overload-c++ operator overloading (full)