web analytics

Operator Overloading in C++

Options

codeling 1599 - 6654
@2016-01-07 14:13:28

Operator overloading is one of the advanced concepts of C++. This feature allows you redefine or overload most of the built-in operators available in C++, thus a programmer can use operators with user-defined types as well.

When you use an expression like ‘2 +3', you know that the answer will be the sum of two integers. This is because the compiler knows how to interpret the + operator when used with integers. But, what if you want to do something like ‘obj1 = obj2 + obj3' (where all these are objects of same class) ? How + operator should work in this case? The answer is through operator overloading.

Syntax

Overloaded operators are functions with special names the keyword operator followed by the symbol for the operator being defined.

Point operator+(const Point&);

declares the addition operator that can be used to add two Point objects and returns final Point object.

Most overloaded operators may be defined as ordinary non-member functions or as class member functions. In case we define above function as non-member function of a class then we would have to pass two arguments for each operand as follows:

Point operator+(const Point&, const Point&);

 

Example

Following is the example to show the concept of operator over loading using a member function.

class Point
{
public:
 Point() : _x(0), _y(0)
 {}

 Point(const int& x, const int& y)
  :_x(x), _y(y)
 {
 }

 int X()
 {
  return _x;
 }

 void SetX(int x)
 {
  _x = x;
 }

 int Y()
 {
  return _y;
 }

 void SetY(int y)
 {
  _y = y;
 }

 Point operator+(const Point& p)
 {
  Point point;
  point._x = this->_x + p._x;
  point._y = this->_y + p._y;

  return point;
 }

 Point operator-(const Point& p)
 {
  Point point;
  point._x = this->_x - p._x;
  point._y = this->_y - p._y;

  return point;
 }

private:
 int _x;
 int _y;

};

 

int main()
{
 Point p1(1, 1);
 Point p2(2, 2);

 Point p3 = p1 + p2;

}

@2016-01-07 14:33:53

Operator Overloading and Chaining in C++

When designing an overloaded operator, think about whether it needs to be chained. For example:

MyString cstr = "a" + "b" + "c";

The MyString class's operator returns a reference to the MyString class.

A partial implementation might be:

class MyString
{
public:
   MyString& operator+(const char* buf); 
   ..........
}; 
MyString& MyString::operator+(const char* buf)
{
     // code to add the char* to the string
     return *this;
}

For example, the following code implements an overloaded operator+(int delta) method in above Point class:

Point& operator+(int delta)

{

this->_x += delta;

this->_y += delta;

return *this;

}

After that, you can try thie following addition:

Point p4(4, 4);

Point p5 = p4 + 4 + 4;

@2016-01-26 23:16:43

The following set of operators is commonly overloaded for user-defined classes:

  • = (assignment operator)
  • + - * (binary arithmetic operators)
  • += -= *= (compound assignment operators)
  • == != (comparison operators)

The operators :: (scope resolution), . (member access), .* (member access through pointer to member), and ?: (ternary conditional) cannot be overloaded.

@2016-01-27 18:05:49

Assignment Operator =

The assignment operator has a signature like this:

  class MyClass
  {
    public:
    ...
    MyClass& operator=(const MyClass &rhs);
    ...
  }

  MyClass a, b;
  ...
  b = a;   // Same as b.operator=(a);

Notice that the = operator takes a const-reference to the right hand side of the assignment. The reason for this should be obvious, since we don't want to change that value; we only want to change what's on the left hand side.

Also, you will notice that a reference is returned by the assignment operator. This is to allow operator chaining. You typically see it with primitive types, like this:

  int a, b, c, d, e;

  a = b = c = d = e = 42;

This is interpreted by the compiler as:

  a = (b = (c = (d = (e = 42))));

In other words, assignment is right-associative. The last assignment operation is evaluated first, and is propagated leftward through the series of assignments. Specifically:

  • e = 42 assigns 42 to e, then returns e as the result
  • The value of e is then assigned to d, and then d is returned as the result
  • The value of d is then assigned to c, and then c is returned as the result
  • etc.

Now, in order to support operator chaining, the assignment operator must return some value. The value that should be returned is a reference to the left-hand side of the assignment.

Notice that the returned reference is not declared const. This can be a bit confusing, because it allows you to write crazy stuff like this:

  MyClass a, b, c;
  ...
  (a = b) = c;  // What??

At first glance, you might want to prevent situations like this, by having operator= return a const reference. However, statements like this will work with primitive types. And, even worse, some tools actually rely on this behavior. Therefore, it is important to return a non-const reference from your operator=. The rule of thumb is, "If it's good enough for ints, it's good enough for user-defined data-types."

So, for the hypothetical MyClass assignment operator, you would do something like this:

  // Take a const-reference to the right-hand side of the assignment.
  // Return a non-const reference to the left-hand side.
  MyClass& MyClass::operator=(const MyClass &rhs) {
    ...  // Do the assignment operation!

    return *this;  // Return a reference to myself.
  }

Remember, this is a pointer to the object that the member function is being called on. Since a = b is treated as a.operator=(b), you can see why it makes sense to return the object that the function is called on; object a is the left-hand side.

But, the member function needs to return a reference to the object, not a pointer to the object. So, it returns *this, which returns what this points at (i.e. the object), not the pointer itself. (In C++, instances are turned into references, and vice versa, pretty much automatically, so even though *this is an instance, C++ implicitly converts it into a reference to the instance.)

Comments

You must Sign In to comment on this topic.


© 2024 Digcode.com