Compound Assignment Operators
Tip
If a class defines +
, -
, *
, and /
, then it is a
good practice to also define the corresponding compound assignment
operators, +=
, -=
, *=
, and /=
.
The compound assignment operators provide a shorthand, e.g.:
a += b
is the same as
a = a + b
So when we overload the operator, we not only need to do the arithmetic operation, but we need to return a reference to the object we are operating on.
Back to our vector class, this means that our overloaded operator +=
will have
the form:
Vector2d& operator+= (const Vector2d& vec) {
x += vec.x;
y += vec.y;
return *this;
}
(since this
is a pointer, we dereference it and return it via reference).
Here’s a full implementation (adding to our previous vector2d.H
:
#ifndef VECTOR_2D_H
#define VECTOR_2D_H
#include <iostream>
#include <cmath>
class Vector2d {
private:
// our member data
double x;
double y;
public:
// default constructor
Vector2d()
: x{0.0}, y{0.0}
{}
// another constructor
Vector2d(double _x, double _y)
: x{_x}, y{_y}
{}
// the destructor
~Vector2d() {}
// copy and assignment constructors -- we don't need to define
// them, but we explicitly say to use the default
//Vector2d(const Vector2d& vec) = default;
Vector2d(const Vector2d& vec)
: x(vec.x), y(vec.y) {}
// assignment here means that we want to set our current class's
// values to those to the right of the = -- that's the Vector2d
// coming in through the argument list
//Vector2d& operator= (const Vector2d& vec) = default;
Vector2d& operator= (const Vector2d& vec) {
x = vec.x;
y = vec.y;
return *this;
}
// setters
inline void set_x(double _x) {x = _x;}
inline void set_y(double _y) {y = _y;}
// operators
// add two vectors
Vector2d operator+ (const Vector2d& vec) {
Vector2d vec_out(x + vec.x, y + vec.y);
return vec_out;
}
// subtract two vectors
Vector2d operator- (const Vector2d& vec) {
Vector2d vec_out(x - vec.x, y - vec.y);
return vec_out;
}
// unary minus
Vector2d operator- () {
Vector2d vec_out(-x, -y);
return vec_out;
}
// multiplication
// vec * a
Vector2d operator* (double a) {
Vector2d vec_out(a * x, a * y);
return vec_out;
}
// a * vec -- needs to be a friend
friend Vector2d operator* (double a, const Vector2d& vec);
// division by a scalar
Vector2d operator/ (double a) {
Vector2d vec_out(x / a, y / a);
return vec_out;
}
// compound operators
Vector2d& operator+= (const Vector2d& vec) {
x += vec.x;
y += vec.y;
return *this;
}
Vector2d& operator-= (const Vector2d& vec) {
x -= vec.x;
y -= vec.y;
return *this;
}
Vector2d& operator*= (double a) {
x *= a;
y *= a;
return *this;
}
Vector2d& operator/= (double a) {
x /= a;
y /= a;
return *this;
}
// comparison operators
bool operator== (const Vector2d& vec) const {
return x == vec.x && y == vec.y;
}
bool operator!= (const Vector2d& vec) const {
return x != vec.x || y != vec.y;
}
double abs() {
return std::sqrt(x * x + y * y);
}
double dot(const Vector2d& vec) {
return x * vec.x + y * vec.y;
}
// << and >> are not class members, but need access to the member data
friend std::ostream& operator<< (std::ostream& os, const Vector2d& v);
friend std::istream& operator>> (std::istream& is, Vector2d& v);
};
inline
std::ostream& operator<< (std::ostream& os, const Vector2d& vec)
{
os << "(" << vec.x << ", " << vec.y << ")";
return os;
}
inline
std::istream& operator>> (std::istream& is, Vector2d& vec)
{
is >> vec.x >> vec.y;
return is;
}
inline
Vector2d operator*(double a, const Vector2d& vec) {
Vector2d vec_out(a * vec.x, a * vec.y);
return vec_out;
}
#endif
and here’s a driver:
#include <iostream>
#include "vector2d.H"
int main() {
// vectors displancing N, E, S, W
Vector2d v_north(0.0, 1.0);
Vector2d v_east(1.0, 0.0);
Vector2d v_south(0.0, -1.0);
Vector2d v_west(-1.0, 0.0);
// test compound addition -- if we sum up the four vectors above,
// we should get zero
Vector2d v1;
v1 += v_north;
v1 += v_east;
std::cout << "compound addition (intermediate result): " << v1 << std::endl;
v1 += v_south;
v1 += v_west;
std::cout << "compound addition (final result): " << v1 << std::endl;
// test compound subtraction
Vector2d v2(1.0, 1.0);
v2 -= v_north;
std::cout << "compound subtraction: " << v2 << std::endl;
// test compound multiplication
Vector2d v3(2.0, 4.0);
v3 *= 4;
std::cout << "compound multiplication: " << v3 << std::endl;
// test compound division
Vector2d v4(1.0, -5.0);
v4 /= 2;
std::cout << "compound division: " << v4 << std::endl;
}