Operator Overloading


  • "C++ has the ability to provide the operators with a special meaning. The mechanism of giving special meaning to an operator is known as operator overloading."
  • Operator overloading provides for the creation of new definitions for most of the C++ operators. We can create a new language of our own by the creative use of the function and operator overloading techniques.
  • The term overloading means 'providing multiple definitions' .
  • Operators overloading are similar to functions overloading in that they take operands (arguments) and return a value.
  • Most of the built-in C++ operators are already overloaded. For example, the + operator can be used to add two integers, two reals, or two addresses. Therefore, it has multiple definitions.
  • The built-in definitions of the operators are restricted to built-in types.
  • Even user defined types can be overloaded. Overloaded operators are those that have been redefined within a C++ class using the keyword 'operator' followed by an operator symbol. We can overload all the C++ operators except the following:
    • Class member access operator (., .*)
    • Scope resolution operator (::)
    • Size operator (sizeof)
    • Conditional operator ( ?: )

    Defining operator overloading

  • To define additional task to an operator, we must specify what it means in relation to the class to which the operator is applied. This is done with the help of a special function, called operator function, which describes the task. The general form of an operator function is: return type classname :: operator op(arglist) { Function body //task defined } Where return type is the type of value returned by the specified operation and op is the operator being overloaded.
  • The op is preceded by the keyword Operator.
  • Operator op is the function name.

    Overloading Unary Operators

     Unary operators are +, -, ++ and --. 
        The syntax of overloading is:
    return type operator unary operator (arguments) 
    {
    function body
    }
    

    Example
  • In the example the operator is applied once to c1 and twice to c2.
  • Both prefix and postfix notation is used on c2.
  • The function declaration void operator ++() tells the compiler to call this member function whenever the ++ operator is encountered, provided the operand is of type counter.
  • Since member functions can always access the particular object for which they have been called, this operator requires no arguments.
  • Notice that the return type of the operator is void. Therefore, it does not return any value.
  • Hence, it cannot be used in assignment statements as in c1 = c2++;
  • To rectify this, you have to specify the return type as the name of the object, create a temporary object and return it. This is shown in the example. In this program, operator overloading is done as follows:
    1. member data count is incremented.
    2. a new item temp is created of counter type.
    3. the incremented value is assigned to this variable - temp
    4. temp is returned.
    
  • Expressions like c1 ++ now return a value, so they can be used in other expressions such as
  • c2 = c1 ++; and c2++.get_count();

    Operator Overloading with Return Values


    Example

    Nameless Temporary Objects

  • In the previous example, a temporary object of type counter was created for the exclusive purpose of providing a return value for the ++ operator. The next example shows another approach to the same problem without using a temporary object.
    # include < iostream.h >
    class counter
    {
    private:unsigned int count;
    public:counter() {count = 0;}
    counter (int c) { count=c; }
    int get_count() { return count; }
    counter operator ++()
    {
    count++;
    return (*this);
    }
    };
    void main()
    {
    counter c1 ,c2;
    cout << "\n c1 =" << c1 .get_count() << "\n c2=" << c2.getcount();
     c1++; c2=c1++;
    cout << "\nc1 =" << c1 .get_count() << "\n c2 = "<< c2++.get_count();
    }
    
  • this is a special pointer that points to the current object. It has been used here to return the incremented value without creating a new object.

    Overloading unary minus

    class space {
    int x; int y; int z;
    public:
    void getdata(int a,int b,int c);
    void display();
    void operator-(); };	
    //overload unary minus
    void space :: getdata(int a,int b,int c)  
    {
    x=a; 
    y=b;
    z=c;   }
    void space:: display() {
    cout << x <<" ";
    cout << y <<" ";
    cout << z << " ";   }
    void space :: operator-()  {
    x=-x;
    y=-y;
    z=-z;   }
    main()  {
    space S;
    S.getdata(10,-20,30);
    cout << "S= ";
    S.display();
    -S; //activates operator-()         //function
    cout << "S=";
    S.display();
    return 0;   }
    
    OUTPUT:
    S=10 -20 30
    S=-10 20 -30
    
  • In the above program a – operator when used as a unary, takes just one operand. This operator changes the sign of an operand when applied to a basic data item.
  • Here the function operator-() takes no argument.
  • It changes the sign of data members of the object S.
  • Since the function is a member function of same class, It can directly access the members of the object which activated it.
  • The statement like
  • S2= -S1 will not work. Because, the function operator-() does not return any value.

    Limitation of Increment Operators

  • When applied to basic data types prefix and postfix operators are two different operators. But when they are overloaded there is no distinction between prefix and postfix notation.
  • The expression c2 = c1 ++ has exactly the same effect as c2 = ++c1;
  • In both cases c1 is assigned to c2. If you need the basic data type implementation for the overloaded function, then it requires two overloaded operators, one for prefix and one for postfix.
  • operator ++(); //prefix. operator ++ (int); // postfix.
  • The second declaration uses a dummy int argument, which is set to 0 automatically by the postfix ++ operator. This extra argument allows the compiler to distinguish the two forms.

    Overloading Arithmetic Operators

  • The functional notation [ex: C=sum (A+B)] can be replaced by a natural looking expression.
  • Ex: C= A+B;
  • By overloading the + operator using an operator+() function.

    Example

    Overloading Comparison Operators

  • Just as the arithmetic operators have been overloaded, the relational operators can also be overloaded.
  • The following example shows how to overload the 'Equal to' (==) operator.

    Overload == and +

    const int sz=80;		
    enum boolean{false,true};                     
    class string
    {
    char str[80];
    public:
    string(){strcpy(str," ");}
    string(char s[ ]) {strcpy(str,s);}
    void display() {cout << str;}
    void getstr() { gets(str);}
    boolean operator==(string ss)
    {
    return
    (strcmp(str,ss.str)==0)?true:false;
    }
    string operator +(string ss)
    {
    return strcat(str,ss.str);
    }
    };
    void main() {
    string s1,s2,s3;
    int ch;
    cout << "enter the first string\n";
    s1.getstr();
    cout << "enter second string\n";
    s2.getstr();
    do { cout << "Menu";
    cout << "1.compare two strings\n";
    cout << "2.concatinate two strings\n";
    cout << "enter your choice\n";
    cin >> ch;
    switch(ch) {
    case 1:if(s1==s2)
           cout << "strings are equal\n";
           else
           cout << "strings are not equal\n";
           break;
    case 2:s3=s1+s2;
           cout << "concatenated string is\n";
           s3.display();
           break;   }
    }while(ch==1);
    getch(); }
    

    Overloading Assignment Operator

  • In the following example, you shall overload the += operator. This operator combines the addition and assignment into one step.
    Example
  • In the operator += ( ) function in the above example, the object that takes on the value of the sum is the object of which the function is a member.

    Data Conversion

  • The = operator will assign a value from one variable to another. In statements like i1 = i2; where i1 and i2 are integer variables or user defined objects.
  • Thus, assignments between types - Basic or userdefined, are handled by the compiler without any special instructions.

    Conversions between Basic Types

  • To convert between basic types you use 'casting'. Casting provides explicit conversion between data types.
  • Implicit conversion occurs during evaluation of mixed expressions. Example int x,y; float z; x = (x + y) / z;
  • Since z is a float data type, (x+y) is converted to float implicitly by the compiler. The result is stored in x by implicit conversion to int.

    Conversions between Objects and Basic Types

  • The conversion between object and Basic data types needs a separate routine to define the conversion.
  • The following example shows how to convert between a basic data type and a user defined data type.
    Example

    From Basic To User-Defined

  • The constructor, distance (float meters) converts a basic data type (float) to user defined data type (distance).
  • This function is called when an object of type distance is created with a single argument.
  • The function assumes this argument represents meters.
  • It converts the argument to feet and inches, and assigns the resulting values to the objects data members.


  • From User-Defined To Basic

  • Here, you overload the cast operator, thus creating a conversion function.
  • The function in the example which achieves this is the operator float() function.
  • This operator takes the value of the distance object of which it is a member, converts this value to a float value representing meters and returns this value.
  • This operator is called by the statement, meters = float (dist2)
  • ;
  • The statement meters = dist1 also has the same effect.
  • Here, the compiler starts by looking for an overloaded = operator. But, when it doesn't find one and it sees the conversion function, it uses that instead.


  • Conversions between Objects of Different Classes

  • Conversions between objects of different classes can be done in the same way as the conversion between basic and user-defined types.
  • This topic can be studied under two sections:
  • Conversion routine in source object.
  • Conversion routine in destination object (Constructor with one argument in destination object.)


  • Routine In Source Object

  • When the conversion routine is in the source class, it is implemented as a conversion function.
  • Example shows the conversion between class Rec and class polar.
  • Example
  • In the example shown in the previous slide the statement rec1 = pol1; needs conversion as rec1 and pol1 are objects of two different classes. The conversion function is written as a member function of the polar class (i.e. source object).



  • Routine In Destination Object

  • In the previous example conversion routine was defined in the source class as its member function.
  • The following example illustrates how to define the routine in the destination class.
  • For this, use a constructor with one argument.
  • Example
  • The conversion routine is a one-argument constructor, from the rec class rec(polar p).
  • The function sets the object of which it is a member to the rectangular coordinates that correspond to the polar coordinates of the object received as an argument.
  • To perform the conversion, this constructor must be able to access the data values of the polar object sent as an argument. The polar class contains the two routines to allow this double getr(); and double geta();.
  • The statement rec1 = pol1 in main() of example invokes the one -argument constructor and the conversion is done.


  • Precautions While Overloading

  • Use similar meaning: Do not overload i+1 operator for subtraction. It can be confusing to the user.
  • Use similar syntax: For better readability and reusability, try to use syntax similar to the existing usage of the operator.
  • Restrict the number: Too many overloaded operators causes the listing to be less readable instead of more.
  • Avoid ambiguity: Avoid doing the same conversion in more than one way as the compiler will not know which function to use
  • .
  • Not all operators can be overloaded: Operators that cannot be overloaded are
  • :
    :: - Scope resolution operator			
    ?: - Conditional operator
    .*- Pointer to member operator		
    . - Dot operator


    Returning Objects << Previous

    Next >> Inheritance

    Our aim is to provide information to the knowledge seekers. 


    comments powered by Disqus


Footer1