Eric Gunnerson
Microsoft Corporation
June 21, 2001
As a result of the continuation of C # language specification, we will discuss the problem of operator overload this month. Operators overload (unless specified, the rest of this column will be referred to as "overload") means that the user is allowed to write an expression using user-defined types. It allows the user to define the same function as the predefined type.
For example, a code similar to the following is usually needed to add two numbers. Obviously, SUM is two numbers.
INT i = 5;
INT SUM = I J;
If you can use the type of user-defined user-defined type to write the same type of expression, that's of course, it is best:
Complex i = 5;
Complex SUM = i J;
The operator overload allows an operator such as " " to be overloaded (ie specified clear meanings) to user-defined types. If you do not overload, the user needs to write the following code:
Complex i = new complex (5);
Complex Sum = Complex.Add (i, j);
This code can run well, but the COMPLEX type does not work like a predefined type in the language.
Anything has a specific time and place
The operator overload is a language function that is easy to cause misunderstandings, and the programmer is also very different. Some people think that programs written by users will be puzzled, and they should not be attributed to programming languages. Others think it is a very good feature, you can use anywhere.
Both views contain the correct ingredients, but there are also things that are not proper. It should be acknowledged that the operator overload may result in a written program, but according to my experience, even if the operator is not loaded, it is also likely to write a puzzling code. In some cases, not using the overloading or even makes the code more puzzled.
Those who do not divide, and use overloaded people "indeed" in the production of puzzled code.
The use of overload in the language is to simplify the user's class or structure in the concept. The operator can be overloaded only when it helps to improve the readability of the user's written code. Please note that the inspection standards we have said is "clearer", not "smaller". The class that uses the operator overload almost always makes the code more short, but does not make the code clearer each time (ie more readability).
To illustrate this, I created multiple overload examples. You need to read these code carefully, think about which operator is overloaded, and the overloaded operator has performed what operations.
test
1
Bignum n1 = new Bignum ("123456789012345);
Bignum N2 = New Bignum ("11111");
BIGNUM SUM = N1 N2;
B
Matrix m1 = loadingmatrix ();
Matrix m2 = loadingmatrix ();
Matrix Result = m1 * m2;
iii
DBROW ROW = query.execute ();
While (! row.done)
{
Viewer.Add (Row);
Row ;
}
IV
Account Current = FindAccount (IDNUM);
CURRENT = 5;
Answers and discussion
1
In this example, the operation to be executed is obvious. This addition is just adding a predefined type, everyone understands what operations have been performed, so in this example, it is very meaningful to use operator overload.
B
This example demonstrates how the matrix is multiplied. From a conceptually, the matrix multiplication is not completely similar, but it is a clearly defined operation, so anyone who understands the matrix multiplication is not surprised when seeing this overloaded operator.
iii
In this example, the incremental ( ) operator is overloaded, which makes the database line forward to the next line. Anything related to the database is not possible to understand the true meaning of this increment, and this incremental operation is not so obvious.
In this example, the use of overloaded does not make the code easier. If we turn on the following code, the situation is much more:
DBROW ROW = query.execute ();
While (! row.movenext ())
{
Viewer.Add (Row);
}
IV
What meanings do you add things and employees? In this example, the choice is a good method, which will be registered with the number of employees. This is a very bad operator overload.
in principle
When the principle of overloading is quite simple. If the user wants to perform this kind of operation, it should be overloaded.
Overload arithmetic operator
To overload the operator in the C #, specify the function to perform the operation. The function must be defined in the type involved in the operation, and at least one parameter belongs to this type. This prevents an addition or other strange things for INTs from being overloaded.
To demonstrate overload, we will develop a vector. Vector can be considered from the origin to a specific two-dimensional point. Multiple operations can be performed on the vector. The following is a rough definition of this type:
Struct Vector
{
Float x;
Float y;
Public Vector (Float X, Float Y)
{
THIS.X = x;
THIS.Y = Y;
}
}
To actually use, the vector should support the following operations:
The length of obtaining the vector multiplies the vector by having a number to a vector to minimize another vector to calculate two vectors.
Our mission is to determine how the operation should be implemented.
length
There is no meaningful operator for obtaining the length of the vector. The length does not change, so it is very meaningful as an attribute:
Public Float Length
{
get
{
Return ((float) math.sqrt (x * x y * y);
}
}
Take the vector by / divide
The vector multiplies a quite common operation is a quite common operation, and is the operation of the user wants to implement. The following is related code:
Public Static Vector Operator * (Vector Vector, Float MultiPlier)
{
Return (New Vector (Vector.x * Multiplier,
Vector.y * Multiplier);
}
It should be noted that there are many interesting phenomena. First, the operator is a Static function, so it must obtain the value of the two parameters, while a new object must be returned in the result. The name of the operator happens to be "operator", followed by the operator to be overloaded.
Similar to the above code divided by a number of codes.
Adding two vectors
This is a very common vector operation, so it is obvious to overload them.
Public Static Vector Operator (Vector Vector1, Vector Vector2)
{
Return (New Vector (Vector1.x Vector2.x,
Vector1.y vector2.y);
}
The subtraction code is very similar to the above code.
Calculate points
The bottlement of two vectors is a special operation of the vector definition, which cannot be found in the predefined type. In the equation, the point is represented by writing a point between two vectors, so it and any existing operators are not precisely matching. One interest feature of the points is: it gets the value of two vectors, but only returns a simple number. Regardless of whether it is overloaded, the user code is substantially the same. The first line shows the overloaded version being used, and other rows show two alternative versions:
Double V1i = (velocity * center) / (t * t);
Double V1i = Vector.dotproduct (Velocity, Center) / (t * t);
Double V1i = velocity.dotproduct (center) / (t * t);
At this point, it is almost a judgment call. The class I have written is overloaded to the "*" operator for a dottom, but I want to think about it, I think this code is not the most suitable code.
In the first example, Velocity and Center are not very clear, so this is not very clear, this is not very clear (I am looking for an example of using it), notice this) . The second example clearly shows what calculations to perform, I think the code in this example is most appropriate.
The third example is also OK, but I think if the operation is not a member function, the code will be clearer.
Public Static Double DotProduct (Vector V1, Vector V2)
{
Return (v1.x * v2.x v1.y * v2.y);
}
C # and C overload
Compared with C , C # allows the overloaded operator. There are two restrictions. First, member access, member calls (that is, function calls), assignment, and "new" cannot be overloaded because these operations are defined at runtime.
Second, an operator such as "&&", "||", "?:", and composite assignment such as " =" cannot be overloaded, as this will make the code abnormally and complex.
Overloaded conversion
Let's return to the original example:
Complex i = 5;
Complex SUM = i J;
Although I know how to overload the addition operator, we still need to think about the first statement. This can be achieved by overloading the conversion.
Implicit and explicit conversion
C # simultaneously supports implicit and explicit conversions. Implicit conversions are conversions that are always successful, and the reason why their success is usually the range of target types equal to or greater than the source type. The conversion from Short to Int is an implicit conversion. Implicit conversion can be used as part of the assignment statement:
Short svalue = 5;
Long Lvalue = sValue;
Explicit conversions are those that may result in data loss or trigger exceptions. Therefore, explicit conversion requirements for mandatory type conversion:
Long Lvalue = 5;
Short svalue = (short) Lvalue;
When overloading the conversion, the conversion should be determined whether the conversion is implicit or explicit, but it should be understood that the implicit conversion model is safe, and explicit conversion is risky.
Converting the integer value 5 to the conversion definition as follows:
Public Static Implicit Operator Complex (Int Value)
{
Return (New Complex (Value, 1.0));
}
This allows implicit conversions from INT to Complex. Interoperability
The above is the case where the operator is overloaded in C #. Things will become slightly complicated when they involve other languages.
The operator overload is not one of the .NET public language subset of functions, which means that overloading will not be used in some languages. Therefore, it is very important to provide a non-overloaded alternative to perform the same operation in other languages. If your class defines an addition operator, it should also define the same method to name the name similar to the ADD.