Lecture Handout
  Introduction to Programming
  Lecture No. 31
  Deitel & Deitel - C++ How to Program     Chapter 8
  8.2, 8.3, 8.4, 8.6, 8.7
  Summary
    Lecture Overview
    What is Operator Overloading and Why is it Required
    Where is it Relevant to Apply
    Operators to Overload
    Restrictions on Operator Overloading
    Examples of Operator Overloading
    Non-member Operator Functions

    Example Program 1
    Example Program 2
    Tips
  Lecture Overview
  The topic of this lecture is   Operator Overloading. In previous lectures, we discussed
  about it a bit while discussing about references. So we will see in detail what is operator
  overloading, how to overload operators, where it is relevant to apply and what are the
  restrictions on it.
  What is Operator Overloading and Why is it Required? 
  Operator overloading is to allow the same operator to be bound to more than one
  implementation, depending on the types of the operands.
  As you know that there are standard arithmetic operators in C/C++ for addition ( + ),
  subtraction ( - ), multiplication ( * ) and division ( / ). We should only use these operators
  for their specific purposes. If we want to add two ints, say i and j, the addition will take
  place in the following manner i.e. i  +  j. To add two double numbers, we use the same
  operator and write d1 + d2. We may add two floats with the help of the same operator as
  f1 + f2. Similarly other operations of -, * and / on the primitive types (sometimes called
  as native or built-in types) can be employed. In other words, these operators are already
  overloaded for primitive types in C++. But these C++ operators cannot be used for
  classes and their objects. We have to write our own operator functions that can work with
  objects. 
  Let’s take an example of complex numbers. There are two parts of a complex number i.e.
  real and   imaginary. As complex numbers are part of mathematical vocabulary, so the
  mathematical manipulations are done on them like addition, subtraction and
  multiplication. Suppose, we write our own class for complex numbers named Complex,
  but we can’t add two complex numbers c1 and c2 as c1 + c2 because until now we don’t
  know how to write it. Although, we are able to write a function say cadd() to serve this
  purpose.
  Complex   cadd ( Complex c1,  Complex  c2 ) ;
  It accepts two complex numbers as parameters and returns back the resultant complex
  number. But the usage of this function to add two complex numbers is generally clumsy.
  It gets more cumbersome and complex if we want to carry out cascading operations like 
  i + j + k. It is better to use the standard operators of +, -, * and / as they are more readable
  and elegant.
  Where is it Relevant to Apply?
  Firstly, the operator overloading gets relevant whenever there is the application of the
  mathematical functions of addition, subtraction, multiplication and division. Complex
  number is one example of it. As discussed earlier, in case of Date class, the operators can
  be effectively used to get the future or past dates. 
  Secondly, the operators are also used sometimes in case of non-mathematical
  manipulation. The example of String class to manipulate strings help us understand it in
  a better way. The operator + can be used to concatenate two strings. Previously, we used
  strcat() function declared inside   string.h header file to concatenate two strings. As
  compared to   strcat(), the use of    +   to concatenate two strings is definitely easier and
  more readable. But there is a little bit cost associated with this process of operators
  overloading.
  The cost is involved whenever we overload an operator. We have to write a function and
  make use of the operator semantics correctly while implementing the function. This
  means that the function written to overload   +   operator should do addition or
  concatenation of strings in case of String objects. 
  Operators to Overload
   There are two types of operators to overload:
  1.  Unary 
  2.  Binary
  Unary operators are the ones that require only one operator to work. Unary operators are
  applied to the left of the operand. For example, ^, &, ~ and !.
  Binary operators require two operands on both sides of the operator. +,  -,  *,  /,  %, =,  <
  and > are examples of binary operators.
  The complete list of C++ operators that can be overloaded is as follows:
  +      -      *      /      %      ^      & 
  |      ~      !      =      <      >      += 
  -=      *=     /=      %=    ^=      &=    |= 
  <<    >>    >>=    <<=    ==    !=      <= 
  >=     &&   | |      ++    - -     -> *   , 
  [  ]    ( )      new    new[ ]   delete   delete[ ]
  The following operators can’t be overloaded.
  .      :      ::      .*      ?      sizeof
  Let’s start with operator overloading mechanism. Consider an object   date of the   Date
  class. The data member day can be accessed as follows:
  date.day  =   2;
  In this statement, the day data member of the date object is accessed and assigned value
  2. This expression (date.day) is driven by the object name at left. 
  Similarly, while using operators, the statement like   a + b is driven by the object at the
  left. In this case, + operator function for the object a will be called and b object is passed
  explicitly to the + operator function as an argument. The rules of function overloading are
  applied to the operator overloading. We cannot write two   + operator functions with
  exactly identical parameters. Following the overloading rules, the two operator functions
  have to be different by the type or number of arguments. 
  The syntax of the prototype of the overloaded operator function is:
  return-type   operator  operator-symbol    (parameter-list);
  operator is the keyword here. An example of this will be as follows:
  Complex   operator   + (Complex & );
  We sometimes write only operator to refer to the operator function in our discussion.
  Restrictions on Operator Overloading 
  There are some restrictions on operator overloading.
  -  The operator overloading functions for overloading (), [], -> or the assignment (=)
  Operators must  be declared as class members.
  -  The arity (number of operands) cannot be changed. If you are overloading an operator
  that requires two operands e.g. *. It cannot be used as a unary operator that requires
  one operand.
  -  No new operators can be created. Like in Fortran language, we have ** as ‘raise to
  the power (exponent) operator’ but this operator does not exist in C++. Therefore, it
  can’t be overloaded. Hence, only existing operators of C++ are used.
  -  Overloading can’t be performed for the built-in (sometimes called primitive or native)
  data types. For example, we cannot change how two ints are added. That means that
  operators are overloaded to use with defined data types like classes.
  -  Precedence of an operator cannot be changed. For example, the   * has higher
  precedence than +. This precedence cannot be changed. 
  -  Associativity of an operator cannot be changed. If some operator is right associative,
  it cannot be changed to be left associative.
  Examples of Operator Overloading
  Let’s take the complex number’s class Complex and define a + operator function. 
  We know that when we write the following line:
  x   =   y   +   z ;
  y and z operands are take part in the addition operation but there is no change in them due
  to this operation. This is the + operator’s functionality. The resultant is being assigned to
  the variable x. This  is assignment operator’s functionality. 
  Now we will discuss a little bit about the assignment operator as well. Let’s say we write
  the following statement for two complex numbers c1 and c2. 
  c1   =   c2 ;
  Here c2 is being assigned to c1. Will this assignment work when we have not written any
  assignment operator function for complex number? Apparently, it looks that the
  statement will produce a compilation error (as there is assignment operator defined by us)
  but this is not true. Whenever, we write our own class and compile it, the compiler
  automatically generates a default assignment operator. The default assignment operator
  makes a member to member assignment. This works fine unless there is a pointer data
  member inside our class and that pointer is pointing to some data inside memory. For that
  case (when there is a pointer data member) we have to write our own assignment operator
  otherwise the default assignment operator works fine for us. That will be discussed in the
  subsequent lectures. 
  By definition of addition of complex numbers, we know that whenever two complex
  numbers are added, the real part of one number is added into the real part of other
  number. Similarly, the imaginary part of one number is added to the imaginary part of the
  other number. We also know that when a complex number is added to another complex
  number, the resultant is also a complex number consisting of real and imaginary parts.
  This addition of real, imaginary parts and return of resultant complex number is the
  functionality of the + operator function we are going to write.
  Another thing to decide  for this + operator is whether this operator will be a member
  operator or a   friend operator. Normally, operators are member operators but there are
  situations when they cannot be member operators. In case of member operator, following
  is the syntax of its prototype:
  Complex   operator   + (parameter-list);
  For member operator, the object on the left side of the   + operator is driving this   +
  operation. Therefore, the driving object on the left is available by   this pointer to   +
  operator function. But the object on the right is passed explicitly to the + operator as an
  argument. 
  We can define a member operator as under:
  1.   Complex   Complex  ::  operator   + (Complex  c)
  2.   {
  3.   Complex   temp ;
  4.   temp.real   =   real   +   c.real ;
  5.   temp.imag   =   imag   +   c.imag ;
  6.   return   temp ;
  7.   }
  Let’s see this code line by line.
  Line 1 indicates that the return type is   Complex, it is an operator  + function and it is
  accepting a Complex object by value as an argument.
  In line 3, a local Complex object is declared, called temp. 
  In line 4,   real part of the calling object (that is the one, driving) on the left of the   +
  operator is being added to the real part of the object c, where c is passed as an argument.
  In line 5,   imag part of the calling object (that is the one, driving) on the left of the   +
  operator is being added to the imag part of the object c, where c is passed as an argument.
  In line 6, the   Complex object   temp containing the resultant of   + operation is being
  returned by value. 
  In our code, we can write something as:
  Complex   c1, c2, c3 ;
  . . .
  . . .
  c3   =   c1   +   c2 ;
  In the above statement ( c3   =   c1   +    c2; ), c1 is the object that is calling or driving the
  + operator.   c2 object is being passed as an argument to the   + operator. So c1 and c2
  objects are added by the + operator and resultant Complex object containing the addition
  of these two numbers is returned back. That returned Complex object is assigned to the
  c3  Complex object using the default assignment operator (that is created by the C++
  compiler automatically). 
  What happens if we want to add a   double number to a complex number (a instance of
  Complex)? Like the following:
  c3   =   c1   +   d ;
  This + operation is driven by the c1 object of Complex while double number d of type
  double is passed as argument. Therefore, our above written + operator is not useable for
  this operation of addition. We need to overload + operator for accepting a parameter of
  type double, i.e. we need to write another operator function. The definition of this newly
  overloaded + operator is:
  Complex   Complex  ::  operator   + (double  d)
  {
  Complex   temp ;
  temp.real   =   real   +   d ;   // d is added into the real part
  temp.imag   =   imag ;
  return   temp ;
  }
  By now, you should have noticed that operator overloading and function overloading are
  quite similar.
  When we write the following statement:
  c3   =   d   +   c1;
  The operand on the left of + operator is a double number d. Therefore, this + operation
  should be driven by (called by) the double number. Until now, we have not written such
  an operator. Our previously written two + operators were driven by the Complex object.
  Operator functions, not driven by the class type objects, are kept as friends to the class.
  friend is the keyword used to declare such functions. A friend function to a class also
  has access to the private members of that class. 
  friend   Complex    operator   + (double   d, Complex   c)
  {
  Complex   temp;
  temp.real   =   d   +   c.real;   // d is added into the real part of c
  temp.imag   =   c.imag;
  return   temp;
  }
  You might have noticed that all the three overloaded + operator functions are accepting
  and returning variables by value. To make these functions better, we can also use
  references. So our first member + operator’s prototype can be rewritten as:
  Complex&   operator   + (Complex&  c);
  Now this operator function is accepting a complex number   Complex by reference and
  returning a reference to the resultant complex number. 
  As discussed above, in case of assignment, the default assignment operator is used
  because we have not implemented (overloaded) our own assignment operator (‘=’). 
  But in case, we want to perform the following operation where the two operands are
  added and the resultant is assigned to one of them as:
  c1   =   c1   +   c2;
  There is one operator (+=) that can be used to do both the operations of addition and
  assignment instead of doing these operations separately within operator + and operator
  =. So we can overload this one operator (+=) here to make the code more efficient and
  reduce our work. Therefore, instead of writing:
  c1   =   c1   +   c2;
  We will write:
  c1   +=   c2;
  We will write our operator += as:
  void   Complex :: operator   += ( Complex& c )
  {
  real   +=   c.real;
  imag   +=   c.imag;
  }
  Non-member Operator Functions
  Now we are much clear that when an operator function is implemented as a member
  function, the leftmost operator must be a class object or reference to a class object of the
  operator’s class.
  When an operator function is implemented as a non-member function, the left-most
  operand may be an object of the operator’s class, an object of a different class, or a built-
  in type. Now we discuss it in a detailed manner.
  We can always write our operators as non-member functions. As a non-member
  functions, the binary operators like + gets both the operands as arguments. One thing to
  take care of while writing non-member functions that they cannot access the private
  members of classes. Actually, this is just to this reason that we make those non-member
  functions as   friends to the classes whose   private data members are required to be
  accessed. But the question arises, can we write a non-member operator function without
  making it a   friend of a class. The answer to this question is yes; If there are   public
  member functions to access the private data members of the class then they serve the
  purpose. In this case of Complex class, let’s say we have two public member functions:
  double   real( );
  double   imaginary( );
  to access the private data members real and imag respectively. Then we can write non-
  member operator + function as:
  Complex   operator   + (Complex&  c1, Complex&  c2)
  {
  Complex   temp;
  temp.real ( c1.real()   +   c2.real() );
  temp.imaginary ( c1.imaginary()   +   c2.imaginary() );
  return temp;
  }
  But this non-member operation functions without declaring a   friend of the class is
  definitely slower than the member function or a friend one. The reason for this is obvious
  from the code that it is making three additional function calls of real() and imaginary()
  for each private data member. Also it is not easy to write as compared to member
  functions. Therefore, it is recommended to write the member functions for operators
  instead of non-members.
  Let’s take an example where the operators are performing a non-arithmetical operation.
  We are writing a class String for strings manipulation as:
  class String
  {
      private :
          char   string [ 30 ] ;
      public :
          String ( )
          {
                 strcpy ( string , "" ) ;
          }
          void  getString ( )
          {
               cout  <<  "Enter the String : " ;
               cin  >>  string ;
          }
          void displayString ( )
          {
              cout  <<  "The String Is : "  <<  string  <<  endl ;
          }
          // Declaration (prototype) of overloaded sum operator
          String  operator + ( String & s ) ;
  };
  We want to write + operator to concatenate two strings. Firstly, we will see the operator’s
  behavior in ordinary context (behavior with primitive variables for example) and try to
  implement the same behavior for this class. We want to concatenate two strings (two
  String objects) and then assign the resultant string to a new String object. Here is how
  we will write + operator function.
  String String :: operator + ( String &s )
  { 
      String temp;   // Declared object temp of String type
      strcpy ( temp.string , "" );    // Initialized the temp with empty string
      strcat ( temp.string , string );   // Concatenated the driving object’s string to
  // temp object
  strcat ( temp.string , s.string );   // Concatenated the argument’s string to the
  // temp object 
      return   temp;   // Returned the temp object
  }
  As you might have guessed already, the String object on the left will be the one to drive
  this   + operation and the second String object on the left of   + will be passed as an
  argument to this function. Note that we are not doing the error checking here, the size of
  the resultant string   temp may increase the array size   30 ( the array size defined in the
  class).
  Example Program 1
  Rudimentary implementation of a class named Complex class to cater complex numbers.
  A + operator function has been implemented to add two complex numbers.
  /* This program implements the basic class for complex numbers and demonstrates +
  operator function */
  #include <iostream.h>
  class Complex
  {
      private :
          double   real ;     // Real Part
          double   imag ;   // Imaginary Part
      public :
          /* Parameterless Constructor */
          Complex ( )
          {
              cout   <<   "\n Parameterless Constructor called ..." ;
          }
          /* Parameterized Constructor */
          Complex ( double  r, double  i )
          {
              cout   <<   "\n Parameterized Constructor called ...";
              real   =   r ;
              imag   =   i ;
          }
          /* Setter of real data member */
          void   real ( double  r)
          {
              real   =   r ;
          }
          /* Getter of the real data member */
          double   real ( )
          {
                  return real ;
          }
          /* Setter of the imag data member */
          void   imaginary ( double  i )
          {
              imag = i ;
          }
          /* Getter of the imag data member */
          double   imaginary ( )
          {
              return   imag ;
          }
        /* A Function to display parts of a Complex object */
          void   display ( )
          {
              cout   <<  "\n\n Displaying parts of complex number ...";
              cout   <<   "\n Real Part : " << real << endl ;
              cout   <<   " Imaginary Part : " << imag << endl ;
          }
          /* Declaration (prototype) of overloaded sum operator */
          Complex   operator  + ( Complex & c2 ) ;
  };
  Complex  Complex  ::  operator + ( Complex  & c1 )
  { 
      cout   <<   "\n Operator + called ...";
      Complex   temp ;
      temp.real   =   real   +   c1.real ;
      temp.imag   =   imag   +   c1.imag ;
      return   temp ;
  }
  void main ( )
  {
        Complex c1 ( 1 , 2 ) ;    // Consturct an object using the parameterized constructor
        Complex c2 ( 2 , 3 ) ;    // Consturct another object using the parameterized 
                                     // constructor
        Complex result ;  // Construct an object using a parameterless constructor
        result = c1 + c2 ;  // Call the Operator + to add two complex numbers (c1 & c2) 
                                     // and then assign the result to 'result' object
         result.display ( ) ; // Display the result object contents
  }
  The output of the program is as follows:
  Parameterized Constructor called ...
  Parameterized Constructor called ...
  Parameterless Constructor called ...
  Operator + called ...
  Parameterless Constructor called ...
  Displaying parts of complex number ...
  Real Part : 3
  Imaginary Part : 5
  The + operator function can be enhanced to return reference of Complex object. We can
  also implement += operator. += operator and the enhanced operator + are implemented
  as:
  Complex &   Complex  ::  operator + ( Complex &  c1 )
  { 
      real   =   real  +  c1.real ;
      imag   =   imag  +  c1.imag ;
      return   *this;
  }
  // Declaration (prototype) of overloaded sum assignment operator definition
  Complex & Complex :: operator += ( Complex & c2 )
  { 
      real   +=   c2.real ;
      imag   +=   c2.imag ;
      return   *this;
  }
  Example Program 2
  Rudimentary Implementation of String class to manipulate strings. It uses + operator to
  concatenate strings.
  /* This program implements the basic class for strings and demonstrates + operator
  function to concatenate two strings*/
  #include   <iostream.h>
  #include   <string.h>
  class   String
  {
      private :
          char    string [ 30 ] ;   // Array to store string
      public :
          /* Parameterless Constructor */
          String ( )
          {
                 strcpy ( string , "" ) ; 
        }
          /* Getter function of string */
          void   getString ( )
          {
               cout   <<   "Enter the String: " ;
               cin   >>   string ;
          }
          /* Function to display string */
          void   displayString ( )
          {
              cout   <<   "The String is : "   <<   string   <<   endl ;
          }
          // Declaration (prototype) of overloaded sum operator
          String   operator  + ( String & s ) ;
  };
  String   String  ::  operator + ( String &s )
  { 
      String   temp ;
      strcpy ( temp.string , "" ) ;
      strcat ( temp.string , string );
      strcat ( temp.string , s.string );
      return   temp;
  }
  void main ( )
  {
        String   string1 , string2 ;    // Declared two String objects
        string1.getString ( ) ;   // Get string for string1 object
        string2.getString ( ) ;   // Get string for string2 object
        String hold  =  string1 + string2 ; // Concatenate string1 and string2 and store the
  // result in hold object
        hold.displayString ( ) ;   // Display the string
  }
  The output of the above program is as follows:
  Enter the String: Operator
  Enter the String: Overloading
  The String is : OperatorOverloading
  Tips
  -  Operator Overloading is quite similar to Function Overloading. 
  -  There are two types of operators to overload: unary and binary.
  -  C++ built-in operators work for built-in (primitve) types but for user defined data
  types, user has to write his/her own operators.
  -  There are some restriction while performing Operator Overloading. For example,
  only existing C++ operators are overloaded without creating a new one in the
  language. Also, it should not impact the type, semantics (behavior), arity (number of
  operands required), precedence and associativity of the operator. 
  -  For binary member operators, operands on the left drives (calls) the operation.
  -  Operator functions written as non-members but friends of the class, get both the
  operands as their arguments.
  -  Operators can be written as non-members and even without making them friends. But
  this is tedious and less efficient way, therefore, it is not recommended.

Post a Comment

Don't Forget To Join My FB Group VU Vicky
THANK YOU :)

Previous Post Next Post