Operator overloading C++

Posted by Didi Setyapramana On 9:13 PM 0 komentar

Operator overloading

Operator overloading (less commonly known as ad-hoc polymorphism) is a specific case of polymorphism (part of the OO nature of the language) in which some or all operators like +, = or == are treated as polymorphic functions and as such have different behaviors depending on the types of its arguments. Operator overloading is usually only syntactic sugar. It can easily be emulated using function calls.
Consider this operation:

add (a, multiply (b,c))

Using operator overloading permits a more concise way of writing it, like this:

a + b × c

(Assuming the × operator has higher precedence than +.)
Operator overloading provides more than an aesthetic benefit since the language allows operators to be invoked implicitly in some circumstances.
Problems and critics to the use of operator overloading arise because it allows programmers to give operators completely free functionality, without an imposition of coherency that permits to consistently satisfy user/reader expectations, usage of the << operator is an example of this problem.

// The expression  a << 1;

Will return twice the value of a if a is an integer variable, but if a is an output stream instead this will write “1″ to it. Because operator overloading allows the programmer to change the usual semantics of an operator, it is usually considered good practice to use operator overloading with care.
To overload an operator is to provide it with a new meaning for user-defined types. This is done in the same fashion as defining a function. The basic syntax follows (where @ represents a valid operator):

return_type operator@(parameter_list) {      // ... definition  }

Not all operators may be overloaded, new operators cannot be created, and the precedence, associativity or arity of operators cannot be changed (for example ! cannot be overloaded as a binary operator). Most operators may be overloaded as either a member function or non-member function, some, however, must be defined as member functions. Operators should only be overloaded where their use would be natural and unambiguous, and they should perform as expected. For example, overloading + to add two complex numbers is a good use, whereas overloading * to push an object onto a vector would not be considered good style.

Note:
Operator overloading should only be utilized when the meaning of the overloaded operator’s operation is unambiguous and practical for the underlying type and where it would offer a significant notational brevity over appropriately named function calls.

A simple Message Header

// sample of Operator Overloading
#include <string>
class PlMessageHeader
{
std::string m_ThreadSender;
std::string m_ThreadReceiver;
//return true if the messages are equal, false otherwise
inline bool operator == (const PlMessageHeader &b) const
{
return ( (b.m_ThreadSender==m_ThreadSender) &&
(b.m_ThreadReceiver==m_ThreadReceiver) );
}
//return true if the message is for name
inline bool isFor (const std::string &name) const
{
return (m_ThreadReceiver==name);
}
//return true if the message is for name
inline bool isFor (const char *name) const
{
return (m_ThreadReceiver==name);// since name type is std::string, it becomes unsafe if name == NULL
}
};

Note:

The use of the inline keyword in the example
above is technically
redundant, as functions defined
within a class definition like this are implicitly inline

Operators as member functions
Aside from the operators which must be members, operators may be overloaded as member or non-member functions. The choice of whether or not to overload as a member is up to the programmer. Operators are generally overloaded as members when they:
1. change the left-hand operand, or
2. require direct access to the non-public parts of an object.
When an operator is defined as a member, the number of explicit parameters is reduced by one, as the calling object is implicitly supplied as an operand. Thus, binary operators take one explicit parameter and unary operators none. In the case of binary operators, the left hand operand is the calling object, and no type coercion will be done upon it. This is in contrast to non-member operators, where the left hand operand may be coerced.

// binary operator as member function
Vector 2 D Vector 2 D::operator+(const Vector 2 D& right )const {...}
// binary operator as non-member function
Vector 2 D operator+(const Vector 2 D& left , const Vector 2 D& right ) {...}
// binary operator as member function with 2 arguments
friend Vector 2 D operator+(const Vector 2 D& left , const Vector 2 D& right ) {...}
// unary operator as member function
Vector 2 D Vector 2 D::operator-()const {...}
// unary operator as non-member function
Vector 2 D operator-(const Vector 2 D& vec) {...}

Overloadable operators
Arithmetic operators
• + (addition)
• - (subtraction)
• * (multiplication)
• / (division)
• % (modulus)
As binary operators, these involve two arguments which do not have to be the same type. These operators may be defined as member or non-member functions. An example illustrating overloading for the addition of a 2D mathematical vector type follows.

Vector 2 D operator+(const Vector 2 D& left , const Vector 2 D& right )
{
Vector 2 D result;
result.set_x( left .x() + right .x());
result.set_y( left .y() + right .y());
return result;
}

It is good style to only overload these operators to perform their customary arithmetic operation.
Bitwise operators
• ^ (XOR)
• | (OR)
• & (AND)
• ~ (complement)
• <> (shift right, extraction from stream)
All of the bitwise operators are binary, excepting complement, which is unary. It should be noted that these operators have a lower precedence than the arithmetic operators, so if ^ were to be overloaded for exponentiation, x ^ y + z may not work as intended. Of special mention are the shift operators, <>. These have been overloaded in the standard library for interaction with streams. When overloading these operators to work with streams the rules below should be followed:
1. overload <> as friends (so that it can access the private variables with the stream be passed in by references
2. (input/output modifies the stream, and copying is not allowed)
3. the operator should return a reference to the stream it receives (to allow chaining, cout << 3 << 4 << 5)

An example using a 2D vector

friend ostream& operator<<(ostream& out, const Vector 2 D& vec) // output
{
out << "(" << vec.x() << ", " << vec.y() << ")" ;
return out;
}
friend istream& operator>>(istream& in, Vector 2 D& vec) // input
{
double x, y;
in >> x >> y;
vec.set_x(x);
vec.set_y(y);
return in;
}

 

0 Response for the "Operator overloading C++"

Post a Comment