Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,372
On Slideshare
1,372
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
43
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 12 Operator Overloading Let’s explain what operator overloading is all about with an example of a class that represents a date. Would it not be great if we could subtract two date objects and be returned an int representing the number of days elapsing between the two dates. We would like to use the good old subtraction operator – like we do when subtracting numbers. Also we would like the > operator to compare two date objects and tell us which one is larger. The + operator could add a number to a date resulting in a new date object. Thus, operator overloading lets us redefine the existing operators so that they work with classes/objects we create like yyy. We have not yet instructed C# on how to use the trusty old + operator with two yyy objects. Though C# knows how to use the + to add two numbers, it does not know how to add two yyy’s. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy c; c=a+b; } } public class yyy { public int i; public yyy( int j) { i = j; } } Compiler Error a.cs(8,5): error CS0019: Operator ‘+’ cannot be applied to operands of type ‘yyy’ and ‘yyy’ We have created a simple class yyy which has one instance variable i which will distinguish different instances of yyy from each other. The constructor with an int as a parameter initializes i.
  • 2. We have tried to add two objects that look like yyy which does not go down well with C# and it objects to it. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy c; c=a+b; } } public class yyy { public int i; public yyy( int j) { i = j; } public yyy operator + ( yyy x , yyy y) { } } Compiler Error a.cs(18,12): error CS0558: User-defined operators ‘yyy.operator +(yyy, yyy)’ must be declared static and public Error messages can be at times helpful. Our operator + is public but not static. C# demands that all operator overloads be static. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy c; c=a+b; System.Console.WriteLine(c.i); } } public class yyy { public int i; public yyy( int j) { i = j; } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i);
  • 3. yyy z = new yyy(x.i+y.i); return z; } } Output operator + 10 5 15 The word operator as the name of a function, is legal and the only way to overload operators. We follow this word with the operator we want to overload and then the parameters we will call the operator with. + is a binary operator and will need two yyy’s, one on its left and the other on its right. Then at beginning, we give the return value of the operator. In our case we want a + to add two yyy’s and return a third yyy whose i will be the sum of the individual i’s. Thus a+b will call the operator + with x being equal to a and y to b. Thus x.i will have a value 10 and y.i, 5. We are creating a new object z and in the constructor passing 15 i.e. 10 + 5. Thus the i of z will be 15 which is being returned. a + b will now be replaced by the object whose i has a value 15 and c will be equal to this object. Thus c.i will be equal to 15. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy c; c=a+b; System.Console.WriteLine(c.i); } } public class yyy { public int i; public yyy( int j) { i = j; } public static yyy operator = ( yyy x , yyy y) { } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); yyy z = new yyy(x.i+y.i); return z; } } Compiler Error a.cs(19,28): error CS1020: Overloadable binary operator expected
  • 4. The error message is telling us that we cannot overload the assignment operator =. Every class gets a free assignment operator which does a bitwise copy of the variables of the object from the left to the right. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy c = new yyy(2); yyy d; d=a+b+c; System.Console.WriteLine(d.i); } } public class yyy { public int i; public yyy( int j) { i = j; } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); yyy z = new yyy(x.i+y.i); return z; } } Output Operator + 10 5 Operator + 15 2 17 The only change is d = a + b + c. C# gets easily confused with complex statements so it does not read all of it. It sees two operators on the same line. In this case, the same plus. An internal rule tells it to read the plus left to right i.e. it will only see a + b. It will call the operator + with x.i as 10 and y.i as 5 because a’s i is 10 and b’s i is 5. This will create a temporary object like yyy whose i is 15, lets call it zz. The object z is very different from zz. C# then evaluates zz + c. Thus x.i will display 15 and y.i will have the value of c.i i.e. 2. To support multiple invocations of the operator on a single line, the code does not change. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); int d = a + b ;
  • 5. System.Console.WriteLine(d); } } public class yyy { public int i; public yyy( int j) { i = j; } public static int operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); return x.i + y.i; } } Output operator + 10 5 15 C# does not and will never understand what addition of two yyy’s is all about. It is in your hands to decide what the code accomplishes. You decide whether the overloaded + returns a yyy or an int object. The class yyy is your creation not C#’s. Hence you decide what addition means in the context of a yyy class. In this case, we are returning an int unlike earlier where we returned a yyy. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); int d = a + b ; System.Console.WriteLine(d); } } public class yyy { public int i; public yyy( int j) { i = j; } public static int operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); return x.i + y.i; } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); yyy z = new yyy(x.i+y.i);
  • 6. return z; } } Compiler Error a.cs(23,19): error CS0111: Class ‘yyy’ already defines a member called ‘ op_Addition ‘ with the same parameter types You cannot have two operator + overloads which only differ in return types. Also the error messages change the name of the operator from + to op_Addition. When we overloaded functions, the return type was not considered part of the function signature. The same applies for operators. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy d = a + b + 20; System.Console.WriteLine(d.i); } } public class yyy { public int i; public yyy( int j) { i = j; } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); yyy z = new yyy(x.i+y.i); return z; } } Compiler Error a.cs(7,9): error CS0019: Operator ‘+’ cannot be applied to operands of type ‘yyy’ and ‘int’ C# is now telling you that you can add two yyy’s but cannot do the same, i.e. add a yyy and an int as we have not told C# how to do so. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); yyy d = a + b + 20;
  • 7. System.Console.WriteLine(d.i); } } public class yyy { public int i; public yyy( int j) { i = j; } public static yyy operator + ( yyy x , yyy y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i); yyy z = new yyy(x.i+y.i); return z; } public static yyy operator + ( yyy x , int y) { System.Console.WriteLine(“operator + “ + x.i + “ “ + y); yyy z = new yyy(x.i+y); return z; } } Output Operator + 10 5 Operator + 15 20 35 Life is fun in the fast lane. As we could have a large number of functions with the same name but differing number of parameters, ditto for operators. a + b as usual calls the first operator +. This as usual creates a temp object, say zz and now C# reads the line as zz + 20. This matches the second operator + which now gets called. You can have over a million plus operators with differing parameters if you desire. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); if ( a > b ) System.Console.WriteLine(“true”); else System.Console.WriteLine(“false”); } } public class yyy { public int i; public yyy( int j) {
  • 8. i = j; } public static bool operator > ( yyy x , yyy y) { System.Console.WriteLine(“operator < “ + x.i + “ “ + y.i); return x.i > y.i; } } Compiler Error a.cs(20,20): error CS0216: The operator ‘yyy.operator >(yyy, yyy)’ requires a matching operator ‘<‘ to also be defined C# is a romantic at heart and loves pairs. We tried to overload the > operator and C# tells us that we have to also overload the < operator. It makes sense as a user would want to know whether a yyy is greater than or less than another yyy. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); yyy b = new yyy(5); if ( a > b ) System.Console.WriteLine(“true”); else System.Console.WriteLine(“false”); } } public class yyy { public int i; public yyy( int j) { i = j; } public static bool operator > ( yyy x , yyy y) { System.Console.WriteLine(“operator > “ + x.i + “ “ + y.i); return x.i > y.i; } public static bool operator < ( yyy x , yyy y) { System.Console.WriteLine(“operator < “ + x.i + “ “ + y.i); return x.i < y.i; } } Output operator > 10 5 true
  • 9. The operator < returns a bool as we would like to use it as part of an if or a while. In this case we are using it as part of an if and nothing stops us from using the < overloaded for ints and yyy’s to return a bool. What code you write in an operator is entirely your decision. The < operator looks like the + and can take different parameters. To overload the !=, you also have to overload the ==. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); System.Console.WriteLine(a); System.Console.WriteLine(a.ToString()); } } public class yyy { public int i; public yyy( int j) { i = j; } } Output yyy yyy In the first WriteLine function to be called, we are passing the object a whereas the first parameter to WriteLine should be a string. Also we do not get an error and we see yyy displayed. A longtime back we told you that all classes finally derive from object. The class object has a function ToString. Thus calling the ToString function off a produces the same output as the above line. We have not created the ToString function. So either we got a free ToString implementation from C# like we get a free Constructor or the ToString function of object in some way determines the name of our class and returns it as a string. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); System.Console.WriteLine(a); System.Console.WriteLine(a.ToString()); } } public class yyy { public int i; public yyy( int j) {
  • 10. i = j; } public string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Compiler Warning a.cs(17,15): warning CS0114: ‘yyy.ToString()’ hides inherited member ‘object.ToString()’. To make the current method override that implementation, add the override keyword. Otherwise add the new keyword. It is the same warning if a function exists in the base class. Output yyy ToString mukhi WriteLine displays yyy and a.ToString displays mukhi. Which means that they call different ToString functions. The WriteLine(a) calls the ToString of object whereas the second WriteLine calls it of yyy. If we want to override a function in the base class, we have to specifically do so by using the modifier override. If we do not, the default is to call the base class ToString. All this has been explained earlier, in any case. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); System.Console.WriteLine(a); System.Console.WriteLine(a.ToString()); } } public class yyy { public int i; public yyy( int j) { i = j; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output ToString
  • 11. mukhi ToString mukhi Now both the System.Console.WriteLine calls the ToString function of yyy. We would like to convert a yyy into a string or an int for example. These type conversions are a major part of operator overloading. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); System.Console.WriteLine(a); } } public class yyy { public int i; public yyy( int j) { i = j; } public static implicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output operator string string 10 In spite of having a function ToString, it does not get called unlike earlier. After the keyword operator we have the name of a data type i.e. string. This function is called whenever we want to convert our object into a string. The parameter y stands for the object to be converted. In this function we can write whatever code we want to but we must return a string. In our case we return the text string concatenated with the current value of i. Once again, the WriteLine function requires a string class. We are offering a yyy class. C# checks whether there is an operator string which is available to convert a yyy into a string. As there is one, it gets called. The word implicit means that we are indirectly implying that it should be called. Lets explain this with another example. a.cs public class zzz
  • 12. { public static void Main() { yyy a = new yyy(10); string s; s = a; System.Console.WriteLine(s); } } public class yyy { public int i; public yyy( int j) { i = j; } public static explicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Compiler Error a.cs(7,5): error CS0029: Cannot implicitly convert type ‘yyy’ to ‘string’ We have changed the word implicit which means imply. It also means giving a hint with the word explicit which means specify. Had we not changed implicit with explicit, we would have got no error and C# would have called the operator to convert a into a string and initialize s to it. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); string s; s = (string)a; System.Console.WriteLine(s); } } public class yyy { public int i; public yyy( int j) { i = j; }
  • 13. public static explicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output operator string string 10 The () is called a cast and it takes any data type within brackets. We are explicitly asking for a conversion to a string and unlike earlier we are not being implicit but explicit. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); string s; s = (string)a; System.Console.WriteLine(s); System.Console.WriteLine(a); } } public class yyy { public int i; public yyy( int j) { i = j; } public static explicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output operator string string 10
  • 14. ToString mukhi The explicit will get called only when we cast and as we do not have an implicit modifier, the ToString gets called. We get no error if we do not have an implicit modifier. a.cs public class zzz { public static void Main() { yyy a = new yyy(10); string s; s = (string)a; System.Console.WriteLine(s); System.Console.WriteLine(a); } } public class yyy { public int i; public yyy( int j) { i = j; } public static explicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public static implicit operator string(yyy y) { System.Console.WriteLine(“operator string”); return “string “ + y.i; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Compiler Error a.cs(24,15): error CS0557: Duplicate user-defined conversion in class ‘yyy’ We cannot have both the implicit and explicit modifier as two separate functions. Thus you have to decide which one you would want to implement. a.cs public class zzz { public static void Main() {
  • 15. yyy a ; a = 10; } } public class yyy { public int i; public yyy( int j) { i = j; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output a.cs(7,5): error CS0029: Cannot implicitly convert type ‘int’ to ‘yyy’ One more error. Here we are trying to equate a yyy to an int but unlike earlier, we have not created an object like yyy by saying new. We would need someone to create the yyy object and initialize it to 10, an int. a.cs public class zzz { public static void Main() { yyy a ; a = 10; System.Console.WriteLine(a.i); } } public class yyy { public int i; public yyy( int j) { i = j; } static public implicit operator yyy(int v) { System.Console.WriteLine(“operator yyy int “ + v); yyy z = new yyy(v); return z; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; }
  • 16. } Output operator yyy int 10 10 A constructor has the same name as the name of the class. Thus operator yyy may double up as a constructor. When we write a = 10, C# calls this constructor and passes the parameter v a value, 10. Operator yyy has now to create an object that looks like yyy and return it. Thus it does not act like a constructor in the sense that a constructor is responsible for creating the object. In other words, writing a = 10, creates a new object that looks like yyy and initializes it to 10. It is different from what we did earlier as previously the operator did not have to create an object that looks like yyy. In this case it has to. a.cs public class zzz { public static void Main() { yyy a ; a = “Hi”; System.Console.WriteLine(a.i); } } public class yyy { public int i; public yyy( int j) { i = j; } static public implicit operator yyy(int v) { System.Console.WriteLine(“operator yyy int “ + v); yyy z = new yyy(v); return z; } static public implicit operator yyy(string v) { System.Console.WriteLine(“operator yyy string “ + v); yyy z = new yyy(100); return z; } public override string ToString() { System.Console.WriteLine(“ToString”); return “mukhi”; } } Output operator yyy string Hi 100
  • 17. We can have as many operator yyy functions as we like, provided we follow the rules of function overloading. Thus we have two of them, one that takes a string, another that takes an int. In this case as we are writing a = “hi”, the second operator that accepts a string get called. They all have to return an object that looks like yyy. a = (short) 10; Had we written the above line, we will not get any errors. We assumed we will get an error as we do not have an operator yyy which takes a short as a parameter. C# is highly intelligent. It first checks whether we have an operator yyy that matches what we wrote. In no case, there is a match. It will then check whether there is any other way it can prevent an error from being signaled. C# realizes that there is an operator yyy which accepts an int. Thus it converts a short to an int and then calls the operator yyy with the int parameter.