Docstoc

Operator Overloading

Document Sample
Operator Overloading Powered By Docstoc
					Operator Overloading
     Operator Overloading
           Friends




        Junaed Sattar
       October 15, 2008

          Lecture 7
                   Today

    Overloading operators

    Friend functions and classes
          Overloading Operators

    Similar to function overloading

    Operators get additional “power”
    −   formally they have definitions with respect to
        one or more classes
    −   i.e. they apply to classes
               Example scenario
class Complex {
  double real, imaginary;

     public:
       Complex(): real(0.0), imaginary(0.0){
     }
       Complex( double r, double im ) : real(r), 
     imaginary(im){
     }
     ...
};
int main(){
  Complex cm1, cm2(10, 15);
  Complex cm3 = cm1 + cm2;
}
                        But...

    Will cause compiler error:
    opov.cc: In function ‘int main()’:
    opov.cc:30: error: no match for ‘operator+’ in ‘cm1
    + cm2’

    Because the operator '+' has no meaning
    w.r.t. the Complex class!

    Two forms of the same solution:
    −   overload '+' as a non-member function
    −   overload '+' as a member function
                          Form #1

    Overload as a non-member function
    −   const Complex operator+( const Complex
        &c1, const Complex &c2 );
    −   number of operands equals the type of
        operator
         
             one for unary, two for binary and so on
    −   at least one operand must be a class type
    −   can be pass-by-value or -reference, with or
        without const
         
             efficiency concerns
              Form #1: Definition

    Since not a member function, we need
    accessor functions
     −   functions that are declared public and
         provide access to private members

    double Complex::GetReal() const{ return real;}
    double Complex::GetImaginary() const {
    return imaginary;
    }
    const Complex operator+( const Complex &c1, const Complex &c2 )
    {
    double r = c1.GetReal() + c2.GetReal();
    double im = c1.GetImaginary() + c2.GetImaginary();
    return Complex( r, im );
    }
    Special case: Unary operators

    e.g. increment, decrement operators
    −   const Complex operator++( const
        Complex &c);

    But increment/decrement has prefix and
    suffix forms!
    −   this applies only to the prefix form, i.e.
        Complex c2 = ++c1;
                          Form #2

    Overload as a member function
    −   const Complex operator+( const Complex
        &c2 );
    −   number of operands equals one minus the
        type of operator
         
             none for unary, one for binary and so on
    −   the first operand is the calling object itself
         
             hence we omit it as an argument
                Form #2 Definition

    Since a member function, we have direct
    access to class member variables
    const Complex Complex::operator+( const Complex &c2 ){
      double r = this->GetReal() + c2.GetReal();
      double im = this->GetImaginary() + c2.GetImaginary();
      return Complex( r, im );
    }


    Both forms of unary increment/decrement
    can be defined:
     −   const Complex operator++(); // prefix form
     −   const Complex operator++( int dummy ); // suffix form
         The definition?
const Complex Complex::operator++
 (int dummy) {
 ++this­>real;
 ++this­>imaginary;
 return *this;
}
         Why return a constant?

    return statements create temporay
    objects
    −   similar to passing by value

    these temporary objects are assigned to
    the “l-value”
    −   as opposed to r-values

    this is valid:
    Complex c3 = (c1+c2)++; // convince yourself
              Different Classes?

    adding a double to a Complex, or a
    Complex to a double?
    −   does the order matter?

    Yes it does
    −   Complex c1;
        int i = 10;

        c1 = c1 + i; // will not work unless overloaded
        c1 = i + c1; // also has to be overloaded
             More Overloading

    remember, overloading as a member: the
    argument on the left is the calling class

    const Complex Complex::operator+( int i );

    to put the class as 2nd argument: use non-member
    operator functions
               Friends of a class

    not members, but can access
    private/protected elements
    −   friend functions
    −   friend classes

    commonly used for operator overloading
    −   class Complex {
        ...
        friend void Display( const Complex &c);
        ...
        }
                      Define it

    remember, real and imaginary are private
    −   i.e. not directly accessible to non members
        functions
    −   but not so for friends

void Display( const Complex &c )
  {
    cout << c.real << “ + “ << c.imaginary << “i\n”;
  ...
  }
             OpOv with friends
class Complex {
  ...
  friend const Complex operator+( int i, Complex c );
  ...
}


const Complex operator+( int i, Complex c ){
   int added_r = i + c.real;
   int added_i = i + c.imaginary;

      return Complex( added_r, added_i );
    ...
    }
              Friend Classes

    A friend class can access private or
    protected members of the class it is
    friends with

    Similar to friend functions (function-
    class), but more elaborate (class-class)

    Declaration is different
                        Example
class Node{
  int data;
  int key;
     friend class BinaryTree;
     // class BinaryTree can now access data directly
};
class BinaryTree{
  Node *root;
  int find(int key){
  if(root->key == key){
  // no need to go through an accessor function
  return root->data;
}
      // perform rest of find
}
               Almost correct

    But class Node does not know anything
    about class BinaryTree at the point where
    it is declared

    use “forward declaration” before
    declaring class Node

    class BinaryTree;
    class Node{
    ...

    }
         Overloading >> and <<

    Very useful, as an input/output tool
    −   Helps implement serialization

    Goal?
    −   To be able to write statements like
        Complex c;
        cin >> c;
        cout << c <<endl;

    Problem?
    −   Argument on the left is not a user-defined
        object
                   Then, how?

    Use the friend method for overloading

    Canonical forms:
    −   ostream& operator << (ostream& os, const
        Complex& s);
    −   istream& operator >> (istream& is,
        Complex& s);
      For the Complex class
istream& operator >> (istream& is,
 Complex& s)
 {
   is >> s.real >> s.imaginary;
   return is;
 }
//usage:
 Complex c;
 cin >> c;
 // enter the real part followed by the
 imaginary part, separated by a space
 12 45 // that means 12+45i
              The “this” pointer

    keyword this identifies a special type of
    pointer

    Suppose:
    −   object named x of class A
    −   class A has a member function f()

    When calling the function x.f(), the
    keyword this in the body of f() stores the
    address of x
                            Example
struct X {
private:
     int a;
public:
     void Set_a(int a) {
         // The 'this' pointer is used to retrieve 'xobj.a'
         // hidden by the automatic variable 'a'
         this->a = a;
     }
};

				
DOCUMENT INFO