Skip to main content
GameDev.net gamedev.net
🔒 Locked

Operator overloading +=, -=, *=

Started by FrozenSnake Jan 6, 2015 at 4:48 PM 15 replies 5k views
Original Post
FrozenSnake
FrozenSnake

I read on the MSDN that overloading += doesn't work so I should use + instead. But my problem is I already have it overloaded.

I am trying to convert some of my c++ code to c# to make the same program in C#.

Here is my C++ code


MyVector operator+(const MyVector& vec)
{
return MyVector(mX + vec.mX, mY + vec.mY, mZ + vec.mZ);
}
 
void operator += (const MyVector& vec)
{
mX += vec.mX;
mY += vec.mY;
mZ += vec.mZ;
}
 

MyVector operator-(const MyVector& vec)
{
return MyVector(mX - vec.mX, mY - vec.mY, mZ - vec.mZ);
}
 
MyVector operator-()
{
 
return MyVector(-mX, -mY, -mY);
}
 
void operator -=(const MyVector& vec)
{
mX -= vec.mX;
mY -= vec.mY;
mZ -= vec.mZ;
}
 

float operator*(const MyVector& vec)
{
return (mX * vec.mX + mY * vec.mY + mZ * vec.mZ);
}
 
MyVector operator*(const float& f)
{
return MyVector(mX * f, mY * f, mZ * f);
}
 
void operator*=(const float& f)
{
mX *= f;
mY *= f;
mZ *= f;
}
As you can see I do different stuff on the + and += for example. Is there any good way to get this to work in C#?
Washu
Washu
In .Net the modify-assignment operators are automatically overloaded for you to use your implementation of the appropriate operator.

That is... operator += is provided for you when you provide operator +.

In general, for complex value types I would recommend not using operators in that manner (although it can be trivial and simple for starting). If you want a good idea of how to design a math library, look at SlimMath.

Note that with RyuJIT just around the corner, we will soon have SIMD instructions inline in .Net which will replace many of these operations.
In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
frob
frob

I read on the MSDN that overloading += doesn't work so I should use + instead.


That is because C# silently converts the code:

x += y;

into the code:

x = x + y;

Part of that is to help avoid the beginner's c++ bug of forgetting to implement all the corresponding operators, or the more nuanced bug of having slightly different behavior between the two operators.

You just implement your addition operator, subtraction operator, and the rest. The +=, -=, *=, /=, %=, &=, |=, ^=, and other "op plus assign" operators will use your overloaded operation.
FrozenSnake
FrozenSnake

In .Net the modify-assignment operators are automatically overloaded for you to use your implementation of the appropriate operator.

That is... operator += is provided for you when you provide operator +.

In general, for complex value types I would recommend not using operators in that manner (although it can be trivial and simple for starting). If you want a good idea of how to design a math library, look at SlimMath.

Note that with RyuJIT just around the corner, we will soon have SIMD instructions inline in .Net which will replace many of these operations.

I'll take a look and see if I can figure it out.

I read on the MSDN that overloading += doesn't work so I should use + instead.


That is because C# silently converts the code:

x += y;

into the code:

x = x + y;

Part of that is to help avoid the beginner's c++ bug of forgetting to implement all the corresponding operators, or the more nuanced bug of having slightly different behavior between the two operators.

You just implement your addition operator, subtraction operator, and the rest. The +=, -=, *=, /=, %=, &=, |=, ^=, and other "op plus assign" operators will use your overloaded operation.

So I should do something like the code below to get the same behavior?

I haven't been poking around in C# before so a lot of this is new to me.


        public static MyVector operator +(MyVector vec)
        {
            MyVector mv = new MyVector();
            return (new MyVector(mv.mX + vec.mX, mv.mY + vec.mY, mv.mZ + vec.mZ));
        }

// This doesn't work, Type 'SFMLapp.MyVector' already defines a member called 'op_UnaryPlus' with the same parameter types
        public static void operator+(MyVector vec) // += in the c++ code
        {
            MyVector mv = new MyVector();
            mv.mX += vec.mX;
            mv.mY += vec.mY;
            mv.mZ += vec.mZ;
        }
Nypyren
Nypyren
Since operators are static, the argument list should take both the left-hand and right-hand operands:


public static MyVector operator+(MyVector a, MyVector b)
{
    return new MyVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
FrozenSnake
FrozenSnake

This makes me a bit confused:


 public static void operator+(MyVector vec)
        {
            MyVector mv = new MyVector();
            mv.mX += vec.mX;
            mv.mY += vec.mY;
            mv.mZ += vec.mZ;
        }

Will it keep the value from mForce in this example. So I actually add 'x' to w/e value mForce already have or will the "new MyVector()" mess things up?


mForce = mForce + x;

*EDIT BELOW*

Since operators are static, the argument list should take both the left-hand and right-hand operands:

public static MyVector operator+(MyVector a, MyVector b)
{
return new MyVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}

Thanks for clarifying! Will my example above work as it should or should I alter that as well?

DiegoSLTS
DiegoSLTS

Doing different thigns for "+" and "+=" operators is a good way to write unmaintainable code.

Anyone expects that "A += B" is the same as "A = A + B", if you're not working alone you'll probably have to explain the difference between both more than once, and everyone will hate it when a bug is introduced for mistaking the operands.

I'll make something consistent and self documented, "+" and "+=" operators should do the same (either both modify the vector or both return a new MyVector) and add another explicit way to achieve the other behaviour... For example, if "+" adds to itself, you can have a MyVector constructor that takes a vector as "base" and another vector as the increment; or a static method that takes the same 2 vectors, makes a copy of the first one and adds the second one; or even an instance method called "addToNew" that works like your "+" operator in the first post.

Nypyren
Nypyren


 public static void operator+(MyVector vec)
        {
            MyVector mv = new MyVector();
            mv.mX += vec.mX;
            mv.mY += vec.mY;
            mv.mZ += vec.mZ;
        }
Will my example above work as it should or should I alter that as well?



No, your example will:

- Create a new vector (likely with mX=0,mY=0,mZ=0).
- Add vec to the new vector.
- Won't return a value, so all the work it's doing will be lost.

In C#, all overloaded operators have to be static and have to return a value (they never modify a "this" object like you might do in C++).
FrozenSnake
FrozenSnake


 public static void operator+(MyVector vec)
        {
            MyVector mv = new MyVector();
            mv.mX += vec.mX;
            mv.mY += vec.mY;
            mv.mZ += vec.mZ;
        }
Will my example above work as it should or should I alter that as well?

No, your example will:

- Create a new vector (likely with mX=0,mY=0,mZ=0).
- Add vec to the new vector.
- Won't return a value, so all the work it's doing will be lost.

In C#, all overloaded operators have to be static and have to return a value (they never modify a "this" object like you might do in C++).

I have done this now


        public static MyVector operator+(MyVector a, MyVector b)
        {
            a.mX += b.mX;
            a.mY += b.mY;
            a.mZ += b.mZ;
            return a;
        }

Hopefully that works better :)

Nypyren
Nypyren

I have done this now







        public static MyVector operator+(MyVector a, MyVector b)
        {
            a.mX += b.mX;
            a.mY += b.mY;
            a.mZ += b.mZ;
            return a;
        }
Hopefully that works better smile.png



That will compile and run, but it's written in a way that will change if MyVector is a 'struct' or a 'class'. If it's a 'struct' it will work fine, but if it's a class, the changes made to 'a' will be permanent!

If MyVector is a class, and someone wrote the following code to use your operator:

A = B + C;

what actually would happen would be equivalent to this:

B += C; // B is modified! That's bad.
A = B;

Typically, users of the operator+ expect both of the input variables to be *unchanged* by the operation.


Even if MyVector is a struct, I recommend NOT writing your operator code this way since it's more clear if you don't rely on struct-specific copying behavior.
Nypyren
Nypyren
To reiterate what was said above:

In C#, you *do not* overload the += operator at all. You overload the normal (immutable) addition operator only, and the compiler knows the proper way to call it when you use A + B or A += B later on.
FrozenSnake
FrozenSnake

I do stuff like this in the C++ version:


void Body::AddForce(const MyVector& x)		{ mForce += x; }
void Body::SetVelocity(const sf::Vector2f& vec) { mPrevPos = mPos - vec * mFrames; }
void Body::Update()
{
	if (mID == 0) mForce.SetZ(0);
	if (mCanMove)
	{
		mForce.SetZ(0);
		mBodyShape.setPosition(mPos);
		MyVector tempPos1(mPos);
		MyVector tempPos2(mPrevPos);
		MyVector calc = (tempPos1 * 2.0f - tempPos2 + mForce * mInvertedMass * (mFrames * mFrames));
		mPrevPos = mPos;

		mPos.x = calc.GetX();
		mPos.y = calc.GetY();
	}
	mWindow.draw(mBodyShape);
	DrawTrace();
	ClearForce();
}

At the moment I can't get this code


MyVector calc = (tempPos1 * 2.0f - tempPos2 + mForce * mInvertedMass * (mFrames * mFrames));

To work in the C# version the "tempPos1 * 2.0f - tempPos2" part gives me

Operator "-" cannot be applied to operands of type 'float' and 'SFMLapp.MyVector'

This will probably complain about something else in this line if I fix the first problem. But this is quite confusing.

The operator overloading code looks like this:


public static MyVector operator-(MyVector a, MyVector b)
        {
            a.mX -= b.mX;
            a.mY -= b.mY;
            a.mZ -= b.mZ;
            return a;
        }

        public static float operator -(MyVector a, float b)
        {
            return (a.mX - b + a.mY - b + a.mZ - b);
        }

I am doing a solar system simulation and it works like a charm in C++ and I am trying to translate it to C# and mainly the operators are acting up :/

*EDIT* Currently rewriting the operators to this format:


public static MyVector operator x(MyVector a, MyVector b)
{
    return (new MyVector(a.mX x b.mX, a.mY x b.mY, a.mZ x b.mZ));
}
Nypyren
Nypyren

At the moment I can't get this code




MyVector calc = (tempPos1 * 2.0f - tempPos2 + mForce * mInvertedMass * (mFrames * mFrames));
To work in the C# version the "tempPos1 * 2.0f - tempPos2" part gives me

Operator "-" cannot be applied to operands of type 'float' and 'SFMLapp.MyVector'




It shouldn't be looking for an appropriate operator- overload until it's resolved the multiplication. Have you made a vector*scalar operator yet?:


public static MyVector operator*(MyVector a, float b)
{
    return new MyVector(a.mX * b, a.mY * b, a.mZ * b);
}
FrozenSnake
FrozenSnake

I have made these two, guess I need a MyVector version of the second one


public static MyVector operator*(MyVector a, MyVector b)
{
    return (new MyVector(a.mX * b.mX, a.mY * b.mY, a.mZ * b.mZ));
}

public static float operator*(MyVector a, float b)
{
    return (a.mX * b + a.mY * b + a.mZ * b);
}
// Edit
public static MyVector operator *(MyVector a, float b)        
{
    return (new MyVector(a.mX * b, a.mY * b, a.mZ * b));
}
// Edit

*Edit* now that Calc works too. Hopefully all the operators will work from now on smile.png

If you see anything I do that should be done a different way feel free to point it out.

ChaosEngine
ChaosEngine

public static float operator*(MyVector a, float b)
{
    return (a.mX * b + a.mY * b + a.mZ * b);
}
// Edit
public static MyVector operator *(MyVector a, float b)        
{
    return (new MyVector(a.mX * b, a.mY * b, a.mZ * b));
}
// Edit

You can't have both of these. You have the same signature but different return types.

Consider the following code:


MyVector vec;
float f;

vec * f; // which function to call?

besides your fist method is just wrong. Multiplying a vector by a scalar returns a vector.

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
Bacterius
Bacterius
You also probably want a multiplication operator to multiply a float with a vector (as opposed to a vector with a float) - it'll be the same operation, but C# doesn't impose commutativity on your operators so you have to specify it yourself.
“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.