I have two classes, a vertex and a vector, I am trying to use operators to make life simpler. If you'll examine the vector and vertex classes presented below I'm trying to implement operators in both vertex and vector.
For example
VertexA+VertexB = VectorC //Isn't used that much...
VertexA-VertexB = VectorC //Could be used very frequently
VertexA+VectorB = VertexC //Could be used very frequently
VertexA-VectorB = VertexC //Could be used very frequently
VectorA+VectorB = VectorC //used
VectorA-VectorB = VectorC //used
VectorA+VertexB = VertexC //used
VectorA-VertexB = VertexC //used
If you'll notice there is a circular dependency. In order for the operators of one class to return by value( not by reference or pointer)
I know one work around, express vertexes just as vectors. However I was wondering if there was a different solution because I like the two different classes just for clarity.
#ifndef decimal
#ifdef PRECISION
#define decimal double
#else
#define decimal float
#endif
#endif
class Vector;
class Vertex{
public:
decimal x,y;
const Vertex operator+(const Vector &other);
const Vertex operator-(const Vector &other);
const Vector operator+(const Vertex &other);
const Vector operator-(const Vertex &other);
};
class Vector{
public:
decimal x,y;
const Vector operator+(const Vector &other) const {
Vector result;
result.x=this->x+other.x;
result.y=this->y+other.y;
return result;
}
const Vector operator-(const Vector &other) const {
Vector result;
result.x=this->x-other.x;
result.y=this->y-other.y;
return result;
}
const Vertex operator+(const Vertex &other) const {
Vertex result;
result.x=this->x+other.x;
result.y=this->y+other.y;
return result;
}
const Vertex operator-(const Vertex &other) const {
Vertex result;
result.x=this->x-other.x;
result.y=this->y-other.y;
return result;
}
decimal dot(const Vector &other) const{
return this->x*other.x+this->y*other.y;
}
const decimal cross(const Vector &other) const{
return this->x*other.y-this->y*other.x;
}
};
To make code of this type of things (Arithmetic data types) easy to write, normally I use a set of templates called "Operator overloading helpers", like Boost operators header.
Checkout my implementation.
The advantage of this approach is that the implementation of the operators is coherent (operator+=implementation is coherent with operator+implementation, etc).
In your case, if you only implement Vertex& operator+=(const Vector& other) , Vertex& operator-=(const Vector& other) , Vector& operator+=(const Vector& other) , and Vector& operator-=(const Vector& other); you cover your 3th to 5th cases. How?
Check this code:
//Forward declaration needed:
class Vector;
struct Vertex : public dl32AdditionHelper<Vertex , Vector , true>, //The last parameter is used to enable operator+ simmetry. That is, this covers cases 3 and 7.
public dl32SubstractionHelper<Vertex , Vector , false>, //This covers case 4 (Simmetry si not enabled, see note bellow).
{
float x , y;
//For Vertex + Vector = Vertex
Vertex& operator+=(const Vector& other)
{
x += other.x;
y += other.y;
return *this;
}
//For Vertex - Vector = Vertex
Vertex& operator-=(const Vector& other)
{
x += other.x;
y += other.y;
return *this;
}
};
struct Vector : public dl32AdditionHelper<Vector>, //This covers case 5.
public dl32SubstractionHelper<Vector>, //This covers case 6.
{
float x , y;
//For Vector + Vector = Vector
Vector& operator+=(const Vector& other)
{
x += other.x;
y += other.y;
return *this;
}
//For Vector - Vector = Vector
Vector& operator-=(const Vector& other)
{
x += other.x;
y += other.y;
return *this;
}
};
Thats all.
Symmetry note: Symmetry property implies that operation a # b its equal to b # a, for a given operator #. Arithmetic helpers uses this feature to provide symmetric operators.
For example, matrix algebra: m1 + m2 == m2 + m1, so operator+(const matrix_type_2& m1 , const matrix_type_1& m2) is implemented as m2 + m1 (A call to operator+(const matrix_type_1& m1 , const matrix_type_2& m2)). As you can see, symmetry not works for case 8.
My helpers implementation uses the type of the first parameter as return type of the operator. This is the reason why your other cases are not covered. But that cases implies a conversion from Vector to Vertex or/and viceversa. If you modify the implementation to do that, your all cases could be covered.
Forward declaration actually solved my problems. The compiling issue I got was because my function signatures didn't match correctly in a not obvious way.
Related
I am stuck with regards to the 2 non-member, 2 non-friend multiplication and the addition of the operator overloading functions. I am unsure of how to do it. Could someone please assist in helping me to resolve this? Refer to my codes below. Thank you in advance!
Compiler output:
Point.cpp:208:19: error: passing ‘const CS170::Point’ as ‘this’ argument discards qualifiers [-fpermissive]
return other + value;
^~~~~
Point.cpp: In function ‘CS170::Point CS170::
operator*(double, const CS170::Point&)’:
Point.cpp:215:10: error: ‘double CS170::Point::x’ is private within this context
result.x = value * x;
^
Point.cpp:215:22: error: ‘x’ was not declared in this scope
result.x = value * x;
^
Point.cpp:216:10: error: ‘double CS170::Point::y’ is private within this context
result.y = value * y;
^
Point.cpp:216:23: error: ‘y’ was not declared in this scope
result.y = value * y;
Point.h
#include <iostream> // istream, ostream
namespace CS1100
{
class Point
{
public:
// Point(double X, double Y); // Constructors (2)
explicit Point(double x, double y);
Point();
Point operator+(const Point& other)const ;
Point& operator+(double value);
Point operator*(double value) ;
Point operator%(double value);
Point operator-(const Point& other)const ;
Point operator-(double value);
Point operator^(const Point& other);
Point operator+=(double value);
Point& operator+=(const Point& other) ;
Point& operator++();
Point operator++(int);
Point& operator--();
Point operator--(int);
Point& operator-();
// Overloaded operators (14 member functions)
friend std::ostream &operator<<( std::ostream &output, const Point &point );
friend std::istream &operator>>( std::istream &input, Point &point );
// Overloaded operators (2 friend functions)
private:
double x; // The x-coordinate of a Point
double y; // The y-coordinate of a Point
// Helper functions
double DegreesToRadians(double degrees) const;
double RadiansToDegrees(double radians) const;
};
// Point& Add(const Point& other); // Overloaded operators (2 non-member, non-friend functions)
// Point& Multiply(const Point& other);
Point operator+( double value, const Point& other );
Point operator-( double value, const Point& other );
My source code:
///////////////////////////////////////////////////////////////////////////////
// 2 non-members, non-friends (operators)
double operator+( double value, const Point& other )
{
return other + value;
}
double operator*( double value, const Point& other )
{
Point result;
result.x = value * x;
result.y = value * y;
return result;
}
As far as I understand the discussion to the question, the problem is not really the operators themselves, but the number of allowed member functions being limited – and you already have exceeded this limit.
However, you have quite a number of functions that don't need to be members, for instance:
class Point
{
public:
Point operator+(const Point& other) const
{
return Point(x + other.x, y + other.y);
}
};
Make free functions from all these:
class Point { /*...*/ };
Point operator+(Point const& l, Point const& r)
{
return Point(l.getX() + r.getX(), l.getY() + r.getY());
}
Having moved out all these operators like the one shown above, you get away far enough from the limit so that you can introduce the needed getters:
class Point
{
public:
double getX() { return x; };
double getY() { return y; };
};
If you are willing to rename the member variables, e. g. by adding a prefix, you can follow another pattern:
class Point
{
double m_x, m_y;
public:
double x() { return m_x; };
double y() { return m_y; };
void x(double v) { m_x = v; }; // the corresponding setter
// (for illustration, you might not need it)
};
This latter pattern is quite common, too. Advantage is being shorter for skipping the explicit get or set prefix, disadvantage is exactly losing this explicitness... Decide you, which one you prefer. More important than personal preference is consistency, though, so if there's e. g. a company's convention or common practice, follow that one...
Some of your operators will need to remain members, though, these are all those that modify the current object:
class Point
{
public:
Point& operator+=(const Point& other) /* const */ // NEEDS to be non-const
{
x += other.x;
y += other.y;
return *this; // <- very good hint to spot the ones needing to stay members
}
};
If you have a public copy constructor, you can re-use the operator+= for defining the operator+:
class Point
{
public:
Point(Point const& other) : Point(other.x, other.y) { }
};
Point operator+(Point const& x, Point const& y)
{
Point r(x); // or Point(x.x(), x.y()), if you lack such constructor)
r += y;
return r;
}
Actually, you can even spare the explicit copy by accepting one of the parameters by value:
Point operator+(Point x, Point const& y)
// ^ no reference
{
return x += y;
}
The latter rather for illustration, I'd prefer the two references in given case to keep the symmetry of the interface...
I try to create a custom class used with std::set. I know I need to provide a custom comparator for it so I overloaded the operator<. But when I try to copy the set with the code set<Edge> a; set<Edge> b = a;,
I get the following error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__functional_base:63:21: Invalid operands to binary expression ('const Edge' and 'const Edge')
class Edge {
public:
Edge(int V, int W, double Weight):v(V),w(W),weight(Weight){}
int other(int vertex){ return v ? w : vertex == w;}
int v,w;
double weight;
friend std::ostream& operator<<(std::ostream& out, const Edge& e)
{
out<<e.v<<' '<<e.w<<' '<<"weight:"<<e.weight<<'\n';
return out;
}
bool operator<(const Edge& other)
{
return weight < other.weight;
}
};
Make
bool operator<(const Edge& other) const
as the comparison operator must be marked const. The keys in a std::set are const, so the operator< is invoked on a const instance, hence must be marked const.
This question already has an answer here:
simple c++: How to overload the multiplication operator so that float*myClass and myClass*float works
(1 answer)
Closed 9 years ago.
i'm trying write a polynomial class that can be used for calculation.
class Polynomial
{
public:
Polynomial(QString s); // creates a polynomial with QRegExp
const Polynomial operator+(Polynomial const& rhs); // NOT TESTED
const Polynomial operator+(double d);
const Polynomial operator-(Polynomial const& rhs); //
const Polynomial operator-(double d);
const Polynomial operator-();
private:
void resizeToMin();
QList<int> exp;
QList<double> coeff;
QChar var;
};
i would want to use the Polynomial like this:
Polynomial p("3*x^2 + x^1 -1");
double a = 2.0;
p = p*2 // this works
p = p*a // this works
p = 2*p // DOES NOT WORK
p = a*p // DOES NOT WORK
same for + and -
is this even possible? it would allow me to calculate with polynomials in the same way as with doubles
thanks in advance
Your operators only go one direction as you have them defined. As your class stands, you have the left side always be a Polynomial which won't work for double*Polynomial wherein the double is on the left side.
Since multiplication of polynomials is commutative (I think that's the word...a*b=b*a), you can define an operator like this outside the class:
Polynomial operator+(const double& lhs, const Polynomial& rhs) {
return rhs + lhs; //switch the operation so that the polynomial is on the left hand side
}
It will take in the double as the lefthand side and apply it as if it were the right hand side.
Adapted from this answer: https://stackoverflow.com/a/15741776/1124529
The linked answer also explains a little about doing operations if the operation is not commutative.
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.
I have custom class, that behaves like matrix. Everything works well, except assigning a value from other instance of the same class.
So I can do stuff like:
Matrix a(5,7);
// du stuff with a
Matrix b(5,7);
Matrix d=a+b;
d=a*5;
d[3][2]=1;
//but I can't do this:
double x=d[3][2];
//at this point I get this error:
main.cpp:604:12: error: passing ‘const Matrix’ as ‘this’ argument of ‘Matrix::Proxy Matrix::operator[](int)’ discards qualifiers
Does anybody have any idea, how to fix this? :(
Implementation of my matrix class is here:
class Matrix {
public:
Matrix(int x, int y);
~Matrix(void);
//overloaded operators
Matrix operator+(const Matrix &matrix) const;
Matrix operator-() const;
Matrix operator-(const Matrix &matrix) const;
Matrix operator*(const double x) const;
Matrix operator*(const Matrix &matrix) const;
friend istream& operator>>(istream &in, Matrix& a);
class Proxy {
Matrix& _a;
int _i;
public:
Proxy(Matrix& a, int i) : _a(a), _i(i) {
}
double& operator[](int j) {
return _a._arrayofarrays[_i][j];
}
};
Proxy operator[](int i) {
return Proxy(*this, i);
}
// copy constructor
Matrix(const Matrix& other) : _arrayofarrays() {
_arrayofarrays = new double*[other.x ];
for (int i = 0; i != other.x; i++)
_arrayofarrays[i] = new double[other.y];
for (int i = 0; i != other.x; i++)
for (int j = 0; j != other.y; j++)
_arrayofarrays[i][j] = other._arrayofarrays[i][j];
x = other.x;
y = other.y;
}
int x, y;
double** _arrayofarrays;
};
You currently have one operator[] signature:
Proxy operator[](Matrix *this, int i)
You're trying to call this:
Proxy operator[](const Matrix *, int)
The error is saying that in order to convert from const Matrix * to Matrix *, the const has to be discarded, which is bad. You should provide a const version inside your class:
Proxy operator[](int) const {...}
When inside your class, it gains a first parameter of this, and the const after the parameter list means that the first parameter will be a pointer to a constant object of your class, not a non-constant one.