Struct property operator overload - c++

I'm writing a game in C++ for my Arduino and I've recently found the joys of operator overloading in structs. So far so good! I'm now stuck on the syntax to overload operators on properties. I want to implement something like this so that if my x or y values increase over the screen width I wrap the value back to 0. Many thanks!
// My guess :(
x& operator++(x &newx, int){
if (x == SCREEN_WIDTH - 1)
return 0;
else
return x + 1;
}
My struct definition is:
struct point_t
{
uint8_t x;
uint8_t y;
x& operator++(x &newx, int){
if (x == SCREEN_WIDTH - 1)
return 0;
else
return x + 1;
}
point_t& operator=(const point_t &p)
{
x = p.x;
y = p.y;
return *this;
}
bool operator==(const point_t &p) const
{
return (x == p.x && y == p.y);
}
bool operator!=(const point_t &p) const
{
return !(x == p.x && y == p.y);
}
};

You can't do this exactly as written. The return type of operator should be type.
What you can do is to create a new type, say coordinate, overload operator++ for it, and have your x (and y) have coordinate type, not uint8_t.
Possible solution (based on code by #MrMase):
template<uint8_t MAX>
class coordinate_t
{
private:
int8_t _p;
public:
coordinate_t(int8_t p = 0): _p(p) {}
// Postfix ++
coordinate_t operator++(int)
{
coordinate_t p(_p);
++_p;
if (_p > MAX - 1)
_p = 0;
return p;
}
// Postfix --
coordinate_t operator--(int)
{
coordinate_t p(_p);
--_p;
if (_p < 0)
_p = MAX - 1;
return p;
}
int get() const {return _p;}
};
typedef coordinate_t<SCREEN_WIDTH> xcoordinate_t;
typedef coordinate_t<SCREEN_HEIGHT> ycoordinate_t;
I've made it a template to allow for a simple typedef to define different coordinates; you might also have made MAX a private field and subclass it for different coordinates. In fact, it seems that the template solution is more safe, as it will not allow you to mix different coordinates; however, you might want to reconsider this based on your actual usage.
See full example: http://coliru.stacked-crooked.com/a/5a34261310d05a54

When overloading unary operators (operators with only a single operand, like the increase/decrease operators ++ and --) as member functions, they don't have an argument since they are performed on this. The exceptions being the dummy int arguments for the postfix increase/decrease operators.
The returned value differs depending on which operator you overload, but generally for unary operator you return a reference to object, i.e. *this.
Example
struct point_t
{
int x;
// Prefix increase operator
point_t& operator++()
{
++x;
return *this;
}
// Postfix increase operator
point_t operator++(int)
{
point_t old(*this); // Create new object using copy-constructor
operator++(); // Call prefix operator++ on `this`
return old; // Return old value, before increment
}
...
};
It's all documented in this operator overloading reference, as well as plenty of tutorials all over the Internet.
On an unrelated note, that operator!= can be implemented by using the == operator that you have already implemented:
bool operator!=(const point_t& p) const
{
return !(*this == p);
}
It's always a good idea to use existing operators when creating related operator overloads.

It seems it's not possible to overload a property of an enum so I'm going to do the next best thing: create a new type called xcordinate and overload the ++operator
Thanks very much to everyone who helped. I'm grateful! :)

Related

Why we must overloading += and -= beside just overloading + and - operator?

In c++, why we must overloading +=, -=, +, - operator beside just overloading + and - operator? Here is an example:
In C++, when I create a Point class, I will do:
class Point {
public:
int x, y;
public:
Point(int X, int Y) : x(X), y(Y) {}
//Assignment operator
void operator=(Point a) { x = a.x; y = a.y; }
//The += and -= operator, this seem problematic for me.
void operator+=(Point a) { x += a.x; y += a.y; }
void operator-=(Point a) { x -= a.x; y -= a.y; }
//The + and - operator
Point operator+(Point a) { return Point(x + a.x, y + a.y); }
Point operator-(Point a) { return Point(x - a.x, y - a.y); }
};
But in some other language like C# for example, we don't need to overloading the += and -= operator:
public class Point {
public int x, y;
public Point(int X, int Y) {
x = X; y = Y;
}
//We don't need to overloading =, += and -= operator in C#, all I need to do is overload + and - operator
public static Point operator+(Point a, Point b) { return Point(a.x + b.x, a.y + b.y); }
public static Point operator-(Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
}
And both will work same as c++!
So I already know that if we overloading like c++, we can easier control which operator this class can have. But what else it can do?
I'm also new in c++ and I just learn overloading operator today.
The typical operator+= is more efficient than a = a + b, and cannot be implemented in terms of operator+. It can be the other way around though:
struct foo {
int value = 42;
foo& operator+=(const foo& other) {
this.value += other.value;
return *this;
}
foo operator+(const foo& other) const {
foo result = *this;
result += other; // reuse operator+=
return result;
}
};
Note how operator+ must create a new instance, while operator+= merely adds member of already existing instances.
In general operator+= can do something else entirely and might not be related to operator+ at all.
The same holds for operator-= vs operator-.
The questions that should be asked are rather:
Why C# wont allow overloading assignment operator?
Why C++ can't automatically do += if you have overloaded '+' and '=' operators?
The first question is discussed here with an excellent answer: https://stackoverflow.com/a/599582/6035486
TDLR; Due to garbage collection and reference counting, the compiler must be sure that the left side operand of an assignment statement (which is a reference because in C# class instances are references) is invalidated during the assignment hence its reference count must decrease by one. If user-defined assignment logic is allowed and anything can happen in an assignment operator, this mechanism of garbage collection would not work. Sorry this was supposed to be TLDR.
The answer to the second question is the same reason why defining operator== won't automatically give you operator!= and it should also be defined separately.

C++ Vector Operator Overloading

I am trying to find a simple example program that overloads the following operators of a mathematic vector.
Constructor // create
= (equals) // assign
+; -; +=; -= // add sub
*; /; *=; /= // multi divide
++; -- // plus minus
== // compare
>; >=
<; <=
[] // access a value
Cant seem to find any good simple tutorials. I emphasize the simple because I am only learning this stuff now. If someone could link me or even better program a simple overload for just one of the operators as an example would be incredible!
There are a few things to know when you write operators, which are not as often used with other functions.
The assign operators, for example, will return *this because you change the value of the vector:
class v {
public:
double x_, y_;
v& operator += (const v& rhs)
{
_x += rhs._x;
_y += rhs._y;
return *this;
}
};
Another interesting one, the pre ++ and post ++ are different only because of an unused parameter:
class v {
public:
double x_, y_;
v& operator ++ (); // ++v
v& operator ++ (int); // v++
};
The "equal" (assignment) is another one that is tricky when you use pointers. For a vector, it generally won't be a problem, but if you define a vector V and assign it to itself, you have to be careful:
class v {
public:
double x_, y_;
v& operator = (const v& rhs)
{
if(this != &rhs)
{
x_ = rhs.x_;
y_ = rhs.y_;
}
return *this;
}
};
In your case, the if() will most certainly not be useful, but think about doing something like this:
delete p_;
p_ = new foo;
p_->x_ = rhs.p_->x_;
If &rhs == this, then the delete p_ deleted the rhs pointer! That means accessing it on the 3rd line is a bug.
The rest should be easy enough to work with. The compare operators return bool and are const:
class v {
public:
double x_, y_;
bool operator == (const v& rhs) const
{
return x_ == rhs.x_ && y_ == rhs.y_;
}
};
Although, since C++20, you are expected to only declare the three way comparison operator <=> which allows the compiler to implement all the other comparison operators for you. This one returns a negative number (smaller: a < b), 0 (equal: a == b), or a positive number (larger: a > b).
I'm not sure what makes a vector bigger or smaller, I used the length from (0, 0) in this example:
class v {
public:
double x_, y_;
int operator <=> (const v& rhs) const
{
if(x_ == rhs.x_ && y_ == rhs.y_)
{
return 0;
}
return length() > rhs.length() ? 1 : -1;
}
};
Except for the [] operator. There are two versions of that one:
class v {
public:
// I would imagine you'd use an array but as a simple example...
double x_, y_;
double operator [] (int idx) const
{
return idx == 0 ? x_ : y_;
}
v_ref operator [] (int idx)
{
v_ref v(this, idx);
return v;
}
};
As you can see, the non-constant version of the [] operator returns a reference. This is necessary so you can write something like:
r[3] = 7.3;
r[3] returns that reference, then the assignment of the reference is called with 7.3 as the parameter. (Note that we should probably throw an error if you use 3 as the index when you only have 2 values: 0 and 1--this is not shown here)
class v_ref
{
public:
v *p_;
int i_;
v_ref(v *p, int i)
: p_(p), i_(i)
{
}
operator = (double q)
{
// again, I suppose you'd use an array instead!
if(i_ == 0)
{
p_->x_ = q;
}
else
{
p_->y_ = q;
}
}
};
Assuming you want some security, the vector pointer could make use of a reference counter so you know whether a main vector object gets deleted before all of its reference objects...
Another note: I would imagine that your constructor will allocate an array of double (or use an std::vector<double> type...) If you use new, remember to delete in the destructor and that's when the if() in the assignment operator is very important.

c++ operator overloading logical opertors

Hi I was wondering how I could tackle this problem,
I need to overload +, - and * operators but need to replace them with Logical operators for example;
"+" should use OR
0+0 = 0 , 0+1 = 1, 1+1 = 1 ,1+0 = 1
would i have to place in the overload some sort of if statment?
Any help on how i could do this?
Thanks
They will being using binary as the data type, two matrices with binary as their data
There's no need for an if statement, you just need to return the result of && and ||.
struct A
{
bool val;
bool operator + (const A& other) { return val || other.val; }
bool operator * (const A& other) { return val && other.val; }
};
Note that you can't overload operators for built-in types. At least one of the arguments must be user-defined.
You don't want to overload those operators for integers, or any other built-in types, do you? Because it's impossible. If you have your own class which contains a boolean or integer value then the logic goes something like this:
bool operator + (const MyClass& m1, const MyClass& m2)
{
return m1.GetMyBooleanMember() || m2.GetMyBooleanMember();
}
Overloading operator+(int, int) is not possible, however you can create a new type that wraps an int and has the behavior you want...
struct BoolInt
{
int i;
};
BoolInt operator+(BoolInt x, BoolInt y) { return { x.i || y.i }; }
BoolInt operator*(BoolInt x, BoolInt y) { return { x.i && y.i }; }
BoolInt operator-(BoolInt x, BoolInt y) { return { x.i || !y.i }; } // guessing

C++ STL map container with class key and class value

So suppose I have a class like this one:
class Point
{
private:
int x, y;
public:
void setX(int arg_x) { x = arg_x; }
void sety(int arg_y) { y = arg_y; }
int getX() const { return x; }
int gety() const { return y; }
};
Now I want to have a map like this one:
map<Point, Point> m;
But I need a third parameter. I read in cplusplus that this third parameter is to compare something, but I didn't understand what that something was. Can anyone explain that for me?
You can extend your class with such a method if you don't need a separate compare function
class Point
{
private:
int x, y;
public:
bool operator<( const Point& other) const
{
if ( x == other.x )
{
return y < other.y;
}
return x < other.x;
}
};
By default the stl map orders all elements in it by some notion of ordering. In this case this operator is used. Sometimes you dont have control over the Point class or you might want to use it in two different maps each defines its own ordering. For example one map might sort points by x first and other one might sort by y first. So it might be helpful if the comparison operator is independent of the class Point. You can do something like this.
class Point
{
public:
int x, y;
};
struct PointComparer
{
bool operator()( const Point& first , const Point& second) const
{
if ( first.x == second.x )
{
return first.y < second.y;
}
return first.x < second.x;
}
};
map<Point, Point , PointComparer> m;
What you need is to define an ordering of Point items.
This can be done in different ways :
Overload the operator < for Point
You can provide an overload of the < operator, whose prototype is :
bool operator < (const Point & p_lhs, const Point & p_rhs) ;
For example, for my tests, I used the following one :
bool operator < (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
This is the easiest way, but it assumes, semantically, that the ordering defined above is the right default one.
Providing a functor
If you are unwilling to provide a < operator, or want to have multiple maps, each one with its own ordering, your solution is to provide a functor to the map. This is the third template parameter defined for the map:
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
The functor must have the following signature :
struct MyCompareFunctor
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
// the code for comparison
}
} ;
So, for my tests, I just wrote the following :
struct MyCompare
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() > p_rhs.getX()) { return true ; }
if(p_lhs.getX() < p_rhs.getX()) { return false ; }
return (p_lhs.getY() > p_rhs.getY()) ;
}
} ;
And used it in my map:
std::map<Point, Point, MyCompare> map ;
Et voilĂ ...
Specializing std::less for Point
I see no point in doing this, but it's always good to know: You can specialize the std::less template structure for your Point class
#include <functional>
namespace std
{
template<>
struct less<Point> : binary_function <Point,Point,bool>
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
} ;
}
This has the same effect as overloading the operator <, at least, as far as the map is concerned.
As for the operator < solution above, semantically, this solution assumes that the ordering defined above is the right default one as far as std:less is concerned.
Note that the default std::less implementation calls the operator < of the is templated type. Having one giving different results than the other could be considered as a semantic error.
When you are using a user defined class as key in std::map, in order to determine the position of the elements in the container the map needs the Comparison class: A class that takes two arguments of the key type and returns a bool.
It is basically, a comparison functor/ function which compares two key values.
You don't need third parameter, you just need the operator== and operator<
bool operator<(const Point& other) const{
if ( x == other.x )
return y < other.y;
return x < other.x;
}
bool operator==(const Point& other) const{
return x == other.x && y == other.y;
}
I think the code above gives a little upgrade to #parapura rajkumar's solutions.
class Point{
private:
int x, y;
public:
bool operator<( const Point& other) const{
return ((x < other.x) || (y < other.y));
}
};
What you are saying as third parameter is called "Comparator" in STL.
For default types as keys youy don't need to provide one as compiler
does that job for you.
But for your-defined types you have to provide it OR else how would compiler maintain
the sort order in map/set etc.

Class Operator Overloading

This is a very basic operator overload question.
Say I had a class like this...
class xy
{
public:
double x, y;
XY(double X, double Y) { x = X; y = Y;}
XY operator+(const XY & add) const {
return XY(this->x + add.x, this->y + add.y);
}
XY & operator+=(const XY & add) const {?}
}
}
And I want operator+= do to what its supposed to do (you know, add to the current value of x and y). Wouldn't the code be the same for operator+ and operator +=?
How could it be the same? They do different things.
If you don't care about optimizations you can use += in your + operator implementation:
XY operator + (const XY& right) const
{
XY left(*this);
left += right;
return left;
}
Yep, do the add operation (stick to the += operator), and return a reference to itself. Oh, and this can't be a const method.
XY & operator+=(const XY & add) {
this->x += add.x;
this->y += add.y;
return *this;
}
No. Conventionally, operator+ stores the result in a new object and returns it by value, whereas operator+= adds the right-hand side to *this and returns *this by reference.
The two operators are related -- and can often be implemented in terms of one another -- but they have different semantics and therefore can't have identical implementations.