CSC/ECE 517 Fall 2010/ch5 5a MR: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(100 intermediate revisions by 2 users not shown)
Line 1: Line 1:
=Overloading=
='''Introduction to Overloading '''=
 
Overloading is one of the best ways to implement [http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming polymorphism]. Overloading as such refers to a technique in which more than one [http://en.wikipedia.org/wiki/Subroutine method] (function) having the same name can be present in a program. The compiler will resolve which method to be invoked depending upon the [http://en.wikipedia.org/wiki/Method_signature signature] of the method. This is called '''Method Overloading'''. Another type of overloading is the '''Operator Overloading''' which refers to giving additional meaning to normal C++ operators when they are applied to [http://en.wikipedia.org/wiki/Abstract_data_types Abstract Data Types (ADT)]. An operator can be overloaded by defining a function for it.
 


='''Method Overloading'''=
='''Method Overloading'''=
Many programming languages like C++, Java, C# provide method overloading which allows a programmer to write multiple methods with the same name but that which perform a variety of different tasks. This makes an operation more generic in that, the same operation can now be called upon in different ways depending on the circumstances. A method is overloaded when we can find multiple methods in a single class with the same name but with different number and/or type of parameters that is used to define the methods. The return type of the overloaded methods have to be the same else the compiler would not be able to identify the overloaded methods.
Many programming languages like C++, Java, C# provide method overloading which allows a programmer to write multiple methods with the same name but that which perform a variety of different tasks. This makes an operation more generic in that, the same operation can now be called upon in different ways depending on the circumstances. A method is overloaded when we can find multiple methods in a single class with the same name but with different number and/or type of parameters that is used to define the methods. The return type of the overloaded methods have to be the same else the compiler would not be able to identify the overloaded methods.
Example:
<pre>
  int area( int a );
  int area( double a );
  int area( int a, int b );
  double area( int a ); // not allowed
</pre>
In the above example, the first two methods differe by their parameter types and the third one differs by the number of parameters. The fourth example is considered to be equivalent to the first, so is not an overloaded method.
=='''Constructor Overloading'''==
Overloading [http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) constructors], like overloading other method names, is just the practice of defining more than one constructor for a class, each taking a different set of parameters. In this sense, a [http://en.wikipedia.org/wiki/Copy_constructor copy constructor] is nothing but an overloaded method of the default constructor.
Example:
<pre>
  class Example
  {
    public:
        Example();                  // Default constructor
        Example( Example const &obj);  // Copy constructor
        Example(int a, float b); // Another overloaded constructor
    // ...
  };
  Example obj1;              // default constructed
  Example obj2( obj1 );  // copy constructed
  Example obj3(3,4.5);
</pre>
=='''Advantages Of Method Overloading'''==
*When ever some new features are added in a new version, method over loading can be used to add a new method with support for new version without disturbing the existing methods with features of previous version.
*Apart from the obvious advantage that it makes a method more versatile, method overloading also saves memory.
*One of the main advantages of method overloading is that it increases code readability and tidies the code. Let us consider the example of String.valueOf method[http://www.ggbzw.com/Job/Advantages_of_method_overloading_in_java.shtml [4] ] in Java. Given any type of variables, we can get a String representation  of it by using the String.valueOf method. Some of the overloaded versions of this method are defined as:
<pre>
  static String valueOf(boolean b)
  static String valueOf(char c)
  static String valueOf(long l)
  static String valueOf(Object obj)
</pre>
If overloading was not allowed we'd have methods that look like this:
<pre>
  static String valueOfBoolean(boolean b)
  static String valueOfChar(char c)
  static String valueOfLong(long l)
  static String valueOfObject(Object obj)
</pre>
which is very harder to read than the overloaded solution.
=='''Disadvantages Of Method Overloading'''==
* If not used properly ,such as using functions with the same name for different purposes, method overloading cause considerable confusion.
* The mixing of overloads and default parameter values can also lead to unexpected results. In the example below, both the methods can be called with a single parameter which would lead to confusion.This applies equally to constructors that mix specific overloads and default parameters.
<pre>
    void example(int x);
    void example(int x, int y = 1);
</pre>
*Another problem occurs when mixing integer and pointer types:
<pre>
    void example(int x);
    void example(int * ptr);
</pre>
In the above example, a call to ''example(NULL'') could be taken as ''example'' being passed a zero valued integer or a null pointer value, leading either to the overload of ''example'' taking an int being called or to an ambiguity giving a compiler error, depending on compiler's interpretation of C++. In the case of a constructor it may mean that the object is created in the wrong manner.


='''Operator Overloading'''=
='''Operator Overloading'''=


The ability to define how user defined classes interact with operators applicable to primitive types is called '''Operator Overloading'''. In simple words, it means that a single operator can handle multiple argument types. This will help us to prevent using functional-style syntax for manipulation.
[http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B Operators] can be applied on primitive types. When it is possible to define user-defined classes that can interact with these operators, it is called '''Operator Overloading'''. In simple words, it means that a single operator can handle multiple argument types.  


To define an overloaded operator, a function '''''operator''''' # is defined. The # represents the operator that is to be overloaded.  
To define an overloaded operator, a function '''''operator''''' # is defined. The # represents the operator that is to be overloaded.  
Line 14: Line 78:
The overloading is actually done in C++ by replacing instance of every operator with the a call to the operator function.
The overloading is actually done in C++ by replacing instance of every operator with the a call to the operator function.


Example: int a,b,c;
Example:  
<pre>
        int a,b,c;
         a = b*c;
         a = b*c;
   
</pre>   
It is equivalent to -
It is equivalent to -


Line 26: Line 92:
Examples of such operators are:  
Examples of such operators are:  


* '''::''' => Scope Resolution
* '''::''' => [http://en.wikipedia.org/wiki/Scope_resolution_operator Scope Resolution]
* '''.'''  => Member Selection
* '''.'''  => [http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Member_and_pointer_operators Member Selection]
* '''?:''' => Ternary Conditional
* '''?:''' => [http://en.wikipedia.org/wiki/Conditional_operator Ternary Conditional]
* sizeof  => Size of Object
* sizeof  => [http://en.wikipedia.org/wiki/Sizeof Size of Object]


All the other operators can be overloaded.
All the other operators can be overloaded.
Line 43: Line 109:
=='''Arithmetic Operators'''==
=='''Arithmetic Operators'''==
   
   
It includes +=,-=,*=,/=,%= and their corresponding binaries are +,-,*,/,% respectively. It is easy to implement arithmetic assignment   operators as member functions and using these to implement the binary operators. Usually binary operators are implemented as independent, non-member functions. The problem in making it a member function is that it requires an object to which it can be applied [1].
It includes +=,-=,*=,/=,%= and their corresponding binaries are +,-,*,/,% respectively. Generally arithmetic assignment operators can be implemented as member functions. These can then be used to implement the binary operators that are normally independent, non-member functions. The problem in making it a member function is that it requires an object to which it can be applied [1].


==='''Overloading of Arithmetic Assignment Operator'''===
===='''Overloading of Arithmetic Assignment Operator'''====


Example: [1]
Example: [1]
 
<pre>
const BigInt& BigInt::operator += (const BigInt & rhs)
const BigInt& BigInt::operator += (const BigInt & rhs)
// post condition : rhs has to be added to *this
// post condition : rhs has to be added to *this
Line 55: Line 121:
BigInt a = Factorial(25);
BigInt a = Factorial(25);
BigInt b = Factorial(30);
BigInt b = Factorial(30);
 
</pre>
Then the overloaded function is called as -  
Then the overloaded function is called as -  


           a+=b;
           a+=b;
           BigInt c = (b+=b);  
           BigInt c = (b+=b);  
The arithmetic assignment operators should return a value. The return type should be a reference to avoid copy and it must be a constant.
The arithmetic assignment operators should return a value. The return type should be a [http://en.wikipedia.org/wiki/Reference_(C%2B%2B) reference] and also a constant.


More information on overloading Arithmetic Assignment operators can be obtained from [1].
More information on overloading Arithmetic Assignment operators can be obtained from [1].


==='''Overloading of Binary Operator'''===
===='''Overloading of Binary Operator'''====


Example: [2]
Example: [2]


Let us define a class Matrix.
Let us define a class Matrix.
 
<pre>
class Matrix  
class Matrix  
   {    public :
   {    public :
Line 85: Line 151:
           return result;
           return result;
     }
     }
 
</pre>
The *= operator will scale all the elements in the matrix by a ''double'' factor. The function can now be called as  
The *= operator will scale all the elements in the matrix by a ''double'' factor. The function can now be called as  
   
   
Line 95: Line 161:


Some of the relation operators are <,>,==,!,!=,&& which have a return type of ''bool''.
Some of the relation operators are <,>,==,!,!=,&& which have a return type of ''bool''.
The relational operator overloading functions are generally globally defined so that they can be used without any worry about the order the arguments passed.
The relational operator overloading functions are defined to give a global access so that they can be used without any worry about the order in which the arguments passed.


==='''Overloading of Relational Operators'''===
===='''Overloading of Relational Operators'''====


Example : [2]
Example : [2]
 
<pre>
bool operator==(const Date & lhs, const Date & rhs);
bool operator==(const Date & lhs, const Date & rhs);
bool operator<(const Date &lhs, const Date & rhs);
bool operator<(const Date &lhs, const Date & rhs);


bool operator==(const Date & lhs, const Date & rhs)
bool operator==(const Date & lhs, const Date & rhs)
    {    return lhs.equal(rhs);
{  
    }
   return lhs.equal(rhs);
}


bool operator<(const Date & lhs, const Date & rhs)
bool operator<(const Date & lhs, const Date & rhs)
    {    return lhs.less(rhs);
{
    }
   return lhs.less(rhs);
 
}
</pre>
This shows the declaration and defintion for overloading == and < operator. The function for operator == will return true if lhs is equal to rhs and false otherwise. Similarly, the function for operator < will return true if lhs is less than rhs and  false otherwise.
This shows the declaration and defintion for overloading == and < operator. The function for operator == will return true if lhs is equal to rhs and false otherwise. Similarly, the function for operator < will return true if lhs is less than rhs and  false otherwise.


Line 118: Line 186:
=='''I/O Operators'''==
=='''I/O Operators'''==


Some examples of I/O Operators are << and >> i.e the ostream and istream operators. Both the operators are left-associated, meaning they evaluate the expression from left to right like,
Some examples of I/O Operators are << and >> i.e the [http://en.wikipedia.org/wiki/Iostream ostream and istream operators]. Both the operators are left-associated, meaning they evaluate the expression from left to right like,
 
<pre>
(((cout<<1)<<2)<<endl); [2]
(((cout<<1)<<2)<<endl); [2]
 
</pre>
==='''Overloading of I/O Operators'''===
===='''Overloading of I/O Operators'''====


Example : [2]
Example : [2]
 
<pre>
ostream&operator<<(ostream & out, const BigInt & big)
ostream&operator<<(ostream & out, const BigInt & big)
       {  out<<big.tostring();
       {  out<<big.tostring();
Line 134: Line 202:


cout<<s<<b; // function call
cout<<s<<b; // function call
</pre>


The function overloads the ostream operator << to return the integer value converted to string.
The function overloads the ostream operator << to return the integer value converted to string.
Line 141: Line 210:
=='''Other Overloadable Operators'''==
=='''Other Overloadable Operators'''==


==='''Overloading of Bracket Operator'''===
===='''Overloading of Bracket Operator'''====


The bracket operator returns a reference to the data stored in the class.  
The bracket operator when it is overloaded will return a reference to the data which is stored in the function.  
 
Example :


Example : [2]
<pre>
for(int i =0;i< myVector.size();i++)
for(int i =0;i< myVector.size();i++)
myVector[i]=120;
myVector[i]=120;
 
</pre>
This is equivalent to myVector.operator[](i) = 120;
This is equivalent to  
 
<pre>
myVector.operator[](i) = 120;
</pre>
The overloading function is defined as -  
The overloading function is defined as -  
 
<pre>
char& operator [] (int postion) { }
char& operator [] (int postion) { }
 
</pre>
More information on Overloading of Bracket Operator is obtained usin [2].
More information on Overloading of Bracket Operator is obtained usin [2].


==='''Overloading ''new'' and ''delete'' Operators'''===
===='''Overloading new and delete Operators'''====


This facilitates changing memory allocation at run time i.e how much memory is allocated at run time can be changed. The syntax still remains to be new MyClass and it cannot be overloaded.
This facilitates changing memory allocation at run time i.e how much memory is allocated at run time can be changed. The syntax still remains to be new MyClass and it cannot be overloaded.
Line 164: Line 235:
More information about other overloadable operators can be obtained from [2].
More information about other overloadable operators can be obtained from [2].


=='''Advantages'''== [3]
=='''Advantages'''==  
 


* Enables custom classes to act like primitive types - If we have a class ''vector'' which resembles standard array notation, it will be    possible to array to access the individual elements.
* Enables custom classes to act like primitive types - If we have a class ''vector'' which resembles standard array notation, it will be    possible to array to access the individual elements.
* Enables our code to interact correctly with library and template code - Overloading << to be compatible standard I/Sstream library.
* Enables our code to interact correctly with [http://en.wikipedia.org/wiki/C%2B%2B_Standard_Library library] and [http://en.wikipedia.org/wiki/Template_(C%2B%2B) template] code - Overloading << to be compatible standard I/O Stream library.
* Helps us to prevent using functional-style syntax for manipulation.
* Syntax becomes more intuitive.
* Syntax becomes more intuitive.
* Elegently performs complex operations behind the scenes.
* Elegantly performs complex operations behind the scenes. [3]


=='''Disadvantages'''== [3]
=='''Disadvantages'''==  


* All operator overloaded functions must contain one user-defined type so that the basic meaning of operators is not redefined.
 
* All operator overloaded functions must contain one [http://en.wikipedia.org/wiki/User-defined_type user-defined type] so that the basic meaning of operators is not redefined.
* Some operators cannot be overloaded.
* Some operators cannot be overloaded.
* Cannot define additional operators.
* Cannot define additional operators.
* Cannot change predence or associativity of operators.
* Cannot change [http://en.wikipedia.org/wiki/Order_of_operations precedence] or [http://en.wikipedia.org/wiki/Operator_associativity associativity] of operators.
* Code after operating overloading maybe visiually correct but might contain serious code errors.
* Code after operating overloading maybe visually correct but might contain serious code errors.
* Operators defined by programmers may not be semantically meaningful.
* Operators defined by programmers may not be semantically meaningful.
* Wrong return type may be provided.
* Wrong return type may be provided. [3]


=Conclusion=
='''Conclusion'''=
Though method overloading has its uses, it should not be overused. Often you can get away with fewer overloads than you think because the compiler will convert similar types from one to another. However this may not alway be true: a char to int conversion may not be what you wanted so you may require a specific overload taking a char. So using overloaded methods has to be a cautious design effort.Similarly, because operator overloading allows the original programmer to change the usual semantics of an operator it is considered a good practice to use operator overloading with care.


='''References'''=
='''References'''=
Line 194: Line 269:


[http://171.64.64.250/class/cs193d/handouts/25OperatorOverloading.pdf/] Overloading Relational Operators, Advantages and Disadvantages.
[http://171.64.64.250/class/cs193d/handouts/25OperatorOverloading.pdf/] Overloading Relational Operators, Advantages and Disadvantages.
[http://www.ggbzw.com/Job/Advantages_of_method_overloading_in_java.shtml] Advantages of Method Overloading in Java
[http://en.wikipedia.org/wiki/Function_overloading] Functional Overloading

Latest revision as of 01:57, 4 November 2010

Introduction to Overloading

Overloading is one of the best ways to implement polymorphism. Overloading as such refers to a technique in which more than one method (function) having the same name can be present in a program. The compiler will resolve which method to be invoked depending upon the signature of the method. This is called Method Overloading. Another type of overloading is the Operator Overloading which refers to giving additional meaning to normal C++ operators when they are applied to Abstract Data Types (ADT). An operator can be overloaded by defining a function for it.


Method Overloading

Many programming languages like C++, Java, C# provide method overloading which allows a programmer to write multiple methods with the same name but that which perform a variety of different tasks. This makes an operation more generic in that, the same operation can now be called upon in different ways depending on the circumstances. A method is overloaded when we can find multiple methods in a single class with the same name but with different number and/or type of parameters that is used to define the methods. The return type of the overloaded methods have to be the same else the compiler would not be able to identify the overloaded methods.

Example:

   int area( int a );
   int area( double a ); 
   int area( int a, int b );

   double area( int a ); // not allowed

In the above example, the first two methods differe by their parameter types and the third one differs by the number of parameters. The fourth example is considered to be equivalent to the first, so is not an overloaded method.

Constructor Overloading

Overloading constructors, like overloading other method names, is just the practice of defining more than one constructor for a class, each taking a different set of parameters. In this sense, a copy constructor is nothing but an overloaded method of the default constructor.

Example:

   class Example
   {
     public:
        Example();                   // Default constructor
        Example( Example const &obj);  // Copy constructor
        Example(int a, float b); // Another overloaded constructor
     // ...
   };
   Example obj1;              // default constructed
   Example obj2( obj1 );  // copy constructed
   Example obj3(3,4.5);

Advantages Of Method Overloading

  • When ever some new features are added in a new version, method over loading can be used to add a new method with support for new version without disturbing the existing methods with features of previous version.
  • Apart from the obvious advantage that it makes a method more versatile, method overloading also saves memory.
  • One of the main advantages of method overloading is that it increases code readability and tidies the code. Let us consider the example of String.valueOf method[4 ] in Java. Given any type of variables, we can get a String representation of it by using the String.valueOf method. Some of the overloaded versions of this method are defined as:
   static String valueOf(boolean b) 
   static String valueOf(char c) 
   static String valueOf(long l) 
   static String valueOf(Object obj) 

If overloading was not allowed we'd have methods that look like this:

   static String valueOfBoolean(boolean b) 
   static String valueOfChar(char c) 
   static String valueOfLong(long l) 
   static String valueOfObject(Object obj) 

which is very harder to read than the overloaded solution.

Disadvantages Of Method Overloading

  • If not used properly ,such as using functions with the same name for different purposes, method overloading cause considerable confusion.
  • The mixing of overloads and default parameter values can also lead to unexpected results. In the example below, both the methods can be called with a single parameter which would lead to confusion.This applies equally to constructors that mix specific overloads and default parameters.
    void example(int x);
    void example(int x, int y = 1);
  • Another problem occurs when mixing integer and pointer types:
    void example(int x);
    void example(int * ptr);

In the above example, a call to example(NULL) could be taken as example being passed a zero valued integer or a null pointer value, leading either to the overload of example taking an int being called or to an ambiguity giving a compiler error, depending on compiler's interpretation of C++. In the case of a constructor it may mean that the object is created in the wrong manner.

Operator Overloading

Operators can be applied on primitive types. When it is possible to define user-defined classes that can interact with these operators, it is called Operator Overloading. In simple words, it means that a single operator can handle multiple argument types.

To define an overloaded operator, a function operator # is defined. The # represents the operator that is to be overloaded.

Example: operator +, operator >>

The overloading is actually done in C++ by replacing instance of every operator with the a call to the operator function.

Example:

         int a,b,c;
         a = b*c;

It is equivalent to -

        int a,b,c;
        a.operator = (operator+(b,c));

Some operators cannot be overloaded because of their requirement at compile-time.

Examples of such operators are:

All the other operators can be overloaded.

In a broad sense, operators are classified into -

  • Arithmetic Operators
  • Relational Operators
  • I/O Operators

The operator overloading for each type follows.

Arithmetic Operators

It includes +=,-=,*=,/=,%= and their corresponding binaries are +,-,*,/,% respectively. Generally arithmetic assignment operators can be implemented as member functions. These can then be used to implement the binary operators that are normally independent, non-member functions. The problem in making it a member function is that it requires an object to which it can be applied [1].

Overloading of Arithmetic Assignment Operator

Example: [1]

const BigInt& BigInt::operator += (const BigInt & rhs)
// post condition : rhs has to be added to *this
// *this has to be returned

BigInt a = Factorial(25);
BigInt b = Factorial(30);

Then the overloaded function is called as -

         a+=b;
         BigInt c = (b+=b); 

The arithmetic assignment operators should return a value. The return type should be a reference and also a constant.

More information on overloading Arithmetic Assignment operators can be obtained from [1].

Overloading of Binary Operator

Example: [2]

Let us define a class Matrix.

class Matrix 
   {     public :
          /* other member functions */
          MATRIX &operator *= (double scalar);

         private :
          static const int MATRIX_SIZE =3;
          double entries[MATRIX-SIZE][MATRIX_SIZE];
   };
            
const Matrix operator *(double scalar) const
     {    MyMatrix result = *this;
          result*=scalar;
          return result;
     }

The *= operator will scale all the elements in the matrix by a double factor. The function can now be called as

                     myMatrix = myMatrix * 2.3471;

More information on overloading of binary operators can be obtained from [2].

Relational Operators

Some of the relation operators are <,>,==,!,!=,&& which have a return type of bool. The relational operator overloading functions are defined to give a global access so that they can be used without any worry about the order in which the arguments passed.

Overloading of Relational Operators

Example : [2]

bool operator==(const Date & lhs, const Date & rhs);
bool operator<(const Date &lhs, const Date & rhs);

bool operator==(const Date & lhs, const Date & rhs)
{    
   return lhs.equal(rhs);
}

bool operator<(const Date & lhs, const Date & rhs)
{
   return lhs.less(rhs);
}

This shows the declaration and defintion for overloading == and < operator. The function for operator == will return true if lhs is equal to rhs and false otherwise. Similarly, the function for operator < will return true if lhs is less than rhs and false otherwise.

More information on overloading of Relational Operators can be obtained from [1] and [3].

I/O Operators

Some examples of I/O Operators are << and >> i.e the ostream and istream operators. Both the operators are left-associated, meaning they evaluate the expression from left to right like,

(((cout<<1)<<2)<<endl); [2]

Overloading of I/O Operators

Example : [2]

ostream&operator<<(ostream & out, const BigInt & big)
      {   out<<big.tostring();
          return out;
      }
BigInt b = Factorial(25);
string s = "factorial ";

cout<<s<<b; // function call

The function overloads the ostream operator << to return the integer value converted to string.

More information about overloading of I/O Operators can be obtained from [1] and [2].

Other Overloadable Operators

Overloading of Bracket Operator

The bracket operator when it is overloaded will return a reference to the data which is stored in the function.

Example : [2]

for(int i =0;i< myVector.size();i++)
myVector[i]=120;

This is equivalent to

myVector.operator[](i) = 120;

The overloading function is defined as -

char& operator [] (int postion) { }

More information on Overloading of Bracket Operator is obtained usin [2].

Overloading new and delete Operators

This facilitates changing memory allocation at run time i.e how much memory is allocated at run time can be changed. The syntax still remains to be new MyClass and it cannot be overloaded.

More information about other overloadable operators can be obtained from [2].

Advantages

  • Enables custom classes to act like primitive types - If we have a class vector which resembles standard array notation, it will be possible to array to access the individual elements.
  • Enables our code to interact correctly with library and template code - Overloading << to be compatible standard I/O Stream library.
  • Helps us to prevent using functional-style syntax for manipulation.
  • Syntax becomes more intuitive.
  • Elegantly performs complex operations behind the scenes. [3]

Disadvantages

  • All operator overloaded functions must contain one user-defined type so that the basic meaning of operators is not redefined.
  • Some operators cannot be overloaded.
  • Cannot define additional operators.
  • Cannot change precedence or associativity of operators.
  • Code after operating overloading maybe visually correct but might contain serious code errors.
  • Operators defined by programmers may not be semantically meaningful.
  • Wrong return type may be provided. [3]

Conclusion

Though method overloading has its uses, it should not be overused. Often you can get away with fewer overloads than you think because the compiler will convert similar types from one to another. However this may not alway be true: a char to int conversion may not be what you wanted so you may require a specific overload taking a char. So using overloaded methods has to be a cautious design effort.Similarly, because operator overloading allows the original programmer to change the usual semantics of an operator it is considered a good practice to use operator overloading with care.

References

External Links

[1] Overloading Arithmetic and Relational operators

[2] Overloading Relational and I/O Operators

[3] Overloading Relational Operators, Advantages and Disadvantages.

[4] Advantages of Method Overloading in Java

[5] Functional Overloading