Std Vector C# Assignment Operator Overloading

The latest version of this topic can be found at Operator Overloading.

The keyword declares a function specifying what means when applied to instances of a class. This gives the operator more than one meaning, or "overloads" it. The compiler distinguishes between the different meanings of an operator by examining the types of its operands.

You can redefine the function of most built-in operators globally or on a class-by-class basis. Overloaded operators are implemented as functions.

The name of an overloaded operator is , where is the operator as it appears in the following table. For example, to overload the addition operator, you define a function called . Similarly, to overload the addition/assignment operator, , define a function called .

Redefinable Operators

OperatorNameType
CommaBinary
Logical NOTUnary
InequalityBinary
ModulusBinary
Modulus assignmentBinary
Bitwise ANDBinary
Address-ofUnary
Logical ANDBinary
Bitwise AND assignmentBinary
Function call
Cast OperatorUnary
MultiplicationBinary
Pointer dereferenceUnary
Multiplication assignmentBinary
AdditionBinary
Unary PlusUnary
Increment 1Unary
Addition assignmentBinary
SubtractionBinary
Unary negationUnary
Decrement 1Unary
Subtraction assignmentBinary
Member selectionBinary
Pointer-to-member selectionBinary
DivisionBinary
Division assignmentBinary
Less thanBinary
Left shiftBinary
Left shift assignmentBinary
Less than or equal toBinary
AssignmentBinary
EqualityBinary
Greater thanBinary
Greater than or equal toBinary
Right shiftBinary
Right shift assignmentBinary
Array subscript
Exclusive ORBinary
Exclusive OR assignmentBinary
Bitwise inclusive ORBinary
Bitwise inclusive OR assignmentBinary
Logical ORBinary
One's complementUnary
conversion operatorsUnary

1 Two versions of the unary increment and decrement operators exist: preincrement and postincrement.

See General Rules for Operator Overloading for more information. The constraints on the various categories of overloaded operators are described in the following topics:

The operators shown in the following table cannot be overloaded. The table includes the preprocessor symbols and .

Nonredefinable Operators

Member selection
Pointer-to-member selection
Scope resolution
Conditional
Preprocessor convert to string
Preprocessor concatenate

Although overloaded operators are usually called implicitly by the compiler when they are encountered in code, they can be invoked explicitly the same way as any member or nonmember function is called:

The following example overloads the operator to add two complex numbers and returns the result.

  1. General Rules for Operator Overloading

  2. Overloading Unary Operators

  3. Binary Operators

  4. Assignment

  5. Function Call

  6. Subscripting

  7. Member Access

C++ Operators
Keywords

type operator operator-symbol ( parameter-list )
Point pt; pt.operator+( 3 ); // Call addition operator to add 3 to pt.
// operator_overloading.cpp // compile with: /EHsc #include <iostream> using namespace std; struct Complex { Complex( double r, double i ) : re(r), im(i) {} Complex operator+( Complex &other ); void Display( ) { cout << re << ", " << im << endl; } private: double re, im; }; // Operator overloaded using a member function Complex Complex::operator+( Complex &other ) { return Complex( re + other.re, im + other.im ); } int main() { Complex a = Complex( 1.2, 3.4 ); Complex b = Complex( 5.6, 7.8 ); Complex c = Complex( 0.0, 0.0 ); c = a + b; c.Display(); }

The Crash Course

  • Operator overloading allows us to define how the traditional operators, like +,-,*, and / work for classes and objects that we create.
  • Operator overloading works for these operators: +, -, *, /, %, ++, --, ==, !=, >=, <=, >, and <, and a few others that we haven't talked about before.
  • Operator overloading does not work for these operators: '&&' and '||', the assignment operator '=', the dot operator '.', the new operator, and a few others that we haven't really discussed.
  • An example of overloading the '+' operator looks like this: public static Vector operator +(Vector v1, Vector v2) { return new Vector(v1.X + v2.X, v1.Y + v2.Y); }
  • All operators must be marked public and static.
  • When you overload the relational operators, they must be done in pairs. So if you overload '==', you must also overload '!=', and so on.
  • You can also overload the '[' and ']' indexing operator, but that is done in a slightly different way, and is covered in the next tutorial.

Introduction

We've used a lot of operators (+, -, /, *, ==, +=, …) in our days of programming. They all have built-in functionality that does certain specific things. Mostly, these are defined by math, going back thousands of years. In a few cases, we've seen some not-so-normal uses for these operators, like using the '+' operator for appending ("sticking together") two strings. In math, there's no way to "add" strings together, but yet, in C# we can do it.

In C#, when you create classes, it is possible to define how operators should work with them. This means that if you create an object called Cheese, you can add two Cheese objects together, using the '+' operator, and you get to decide what this means! (Though if you do that, Pepper Jack and Colby better result in Colby-Jack!) This is called "operator overloading", and it is actually a really nice feature of C#. (By the way, C++ allows you to do operator overloading, but Java does not. At least, not yet.)

Some operators can be overloaded, while others cannot. For instance, the '=' operator (assignment operator) cannot be overloaded. You can't define what assignment should do. (And there's a good reason for that. You could really mess stuff up if you were allowed to do that.)

But many other operators can be overloaded. So what operators can be overloaded? Here's a list: +, -, *, /, %, ++, --, ==, !=, >=, <=, >, and <. There's a few others, but we've never talked about them (and they aren't very common at all, so for now, we're skipping them). Additionally, the operators +=, -=, /=, *=, and %= are also overloadable, but when we overload the '+' operator, the '+=' operator is automatically overloaded for us.

Oh, and it is also worth pointing out that the relational operators must be overloaded in pairs—if you overload the == operator, you must also overload the != operator, and if you overload the > operator, you must also overload the < operator as well, and so on.

And one other thing that we should look at is a couple of these operators have a "binary" version, and a "unary" version. For instance the '+' operator. A "binary" version means that it operates on two things. 3 + 4, for example. The '+' applies to two separate numbers, 3 and 4. A "unary" version means that it operates on only one thing. -2, for example. The '-' in this case operates only the 2.

So what can't you overload? The logical operators '&&' and '||', the assignment operator '=', the dot operator '.', the new operator, and a few others that we haven't really discussed.

The '[' and ']' operator (used for indexing) can be overloaded in its own way, using indexers, which we'll look at in the next tutorial.

Overloading Operators

You can overload operators for any class you want. But for the sake of simplicity, I'm going to pick a class that should make some sense for overloading operators. I'm going to do operator overloading for a Point class, which stores an x and y coordinate. If you're familiar at all with vectors in math and physics, then this should make sense to you. So let's start with the basic class:

If you remember from a math or physics class, you can add together two vectors. When you add two vectors together, the result is another vector, but with the x and y components added together.

To overload the '+' operator, we simply add in the following code as a member of the Vector class:

All operator overloads must be public and static, which should make sense, since we want to have access to the operator throughout the program, and since it belongs to the class as a whole, rather than any specific instance of the class. We then specify a return type, Vector in this case. We then use the operator keyword, along with the operator that we're overloading ('+') in this case. We then have two parameters, which are the two sides of the '+' operator.

If we had a unary operator, like '-' (as in the negation operator, which makes things negative) we'd only have one parameter:

Notice, too, that we can have multiple versions of the same operator:

Now you can add a vector and a "scalar" (just a plain old number). Though from a math standpoint, this doesn't make any sense.

The relational operators can be overloaded in the exact same way, only they must return a bool:

Remember that I said that the relational operators must be overloaded in pairs, so if you have a '==' operator overload, you must also have a '!=' operator overload, as shown here, though you can simply call the other operator if you want.

By the way, if you look closely at these operator overloads, you can tell that they are basically just a method. (The only real difference is the operator keyword.) C# is basically just taking any place in code where you use the operator and turning it into a method call. All of this is simply to make things look nice. It is what they call "syntactic sugar".

So our completed class might look something like this:

Now that we've defined our operator overloads, we can use them just like we use operators normally:

What's Next?

Operator overloading is a powerful, but simple trick that can make your code a whole lot more readable. While we're on this topic, we'll next cover indexers, which is a very similar task for the '[' and ']' operators.

usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; namespaceOperatorOverloading{publicclassVector{publicdoubleX{get; set; }publicdoubleY{get; set; }publicVector(doublex, doubley){X = x; Y = y; }}}
publicstaticVectoroperator +(Vectorv1, Vectorv2){returnnewVector(v1.X + v2.X, v1.Y + v2.Y); }
publicstaticVectoroperator -(Vectorv){returnnewVector(-v.X, -v.Y); }
publicstaticVectoroperator +(Vectorv, doublescalar){returnnewVector(v.X + scalar, v.Y + scalar); }
publicstaticbooloperator ==(Vectorv1, Vectorv2){return((v1.X == v2.X) && (v1.Y == v2.Y)); }publicstaticbooloperator !=(Vectorv1, Vectorv2){return !(v1 == v2); }
usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; namespaceOperatorOverloading{publicclassVector{publicdoubleX{get; set; }publicdoubleY{get; set; }publicVector(doublex, doubley){X = x; Y = y; }publicstaticVectoroperator +(Vectorv1, Vectorv2){returnnewVector(v1.X + v2.X, v1.Y + v2.Y); }publicstaticVectoroperator +(Vectorv, doublescalar){returnnewVector(v.X + scalar, v.Y + scalar); }publicstaticVectoroperator -(Vectorv){returnnewVector(-v.X, -v.Y); }publicstaticbooloperator ==(Vectorv1, Vectorv2){return((v1.X == v2.X) && (v1.Y == v2.Y)); }publicstaticbooloperator !=(Vectorv1, Vectorv2){return !(v1 == v2); }}}
Vectora = newVector(5, 2); Vectorb = newVector(-3, 4); Vectorresult = a + b;

0 comments

Leave a Reply

Your email address will not be published. Required fields are marked *