d1 + 4 works but 4 + d1 doesn't even though 4 can be converted implicitly to a GMan. Why aren't they equivalent?
struct GMan
{
int a, b;
GMan() : a(), b() {}
GMan(int _a) : a(_a), b() {}
GMan(int _a, int _b) : a(_a), b(_b) {}
GMan operator +(const GMan& _b)
{
GMan d;
d.a = this->a + _b.a;
d.b = this->b + _b.b;
return d;
}
};
int main()
{
GMan d1(1, 2), d(2);
GMan d3;
d3 = d1 + 4;
d3 = 4 + d1;
}
A call x + y is translated by the C++ compiler into either of the following two calls (depending on whether x is of class type, and whether such a function exists):
Member function
x.operator +(y);
Free function
operator +(x, y);
Now C++ has a simple rule: no implicit conversion can happen before a member access operator (.). That way, x in the above code cannot undergo an implicit conversion in the first code, but it can in the second.
This rule makes sense: if x could be converted implicitly in the first code above, the C++ compiler wouldn’t know any more which function to call (i.e. which class it belongs to) so it would have to search all existing classes for a matching member function. That would play havoc with C++’ type system and make the overloading rules even more complex and confusing.
This answer is correct. Those points then entail the canonical way of implementing such operators:
struct GMan
{
int a, b;
/* Side-note: these could be combined:
GMan():a(),b(){}
GMan(int _a):a(_a),b(){}
GMan(int _a, int _b):a(_a),b(_b){}
*/
GMan(int _a = 0, int _b = 0) : a(_a), b(_b){} // into this
// first implement the mutating operator
GMan& operator+=(const GMan& _b)
{
// the use of 'this' to access members
// is generally seen as noise
a += _b.a;
b += _b.b;
return *this;
}
};
// then use it to implement the non-mutating operator, as a free-function
// (always prefer free-functions over member-functions, for various reasons)
GMan operator+(GMan _a, const GMan& _b)
{
_a += b; // code re-use
return _a;
}
And so on for other operators.
Related
I have a class for which I would like to overload the addition operators. For my use case, it makes sense only to allow addition in the case where the a variable of each object is equal.
What is the best way to handle the case where they are not? Throw an exception, something else?
class A {
private:
int a, b;
public:
A(int a, int b)
:a(a), b(b) {}
A& operator+=(const A& rhs) {
if (this->a == rhs.a) {
this->b += rhs.b;
return *this;
}
else { //this->a != rhs.a
//what should I put here?
}
}
};
.
Edits:
These objects are created at run-time during file io.
These objects represent a data point in a spectrum. It only makes sense to add the intensities of two data points if they are at the same position.
a is limited to the range (-180.0, 360.0)
This smells like a is the property of the type, not a property of the value... What exactly does this class represent?
The minimally viable (IMHO) way to approach this is to make explicit the transition from an "anything goes" type to a "type compatible with a particular value of a". I.e.:
MyClass x(1,2), y(1,5);
x += y; // won't compile
x.makeCompatibleWith(y) += y; // will compile
It's usually a pessimization to have arithmetic operators like += throw. Instead, have something else assume the cost - then the cost is explicit, and you can keep += nothrow. It's also easy to search the project for costly operations (well, makeCompatibleWith is not super expensive, just more expensive than += since it adds the overhead of exception handling).
Assuming that the invalid cases are meant to be caught in testing, the makeCompatibleWith function could assert the condition it requires, but in release builds it would return some dummy object that turns the += into a no-op since it won't modify x - while still keeping += very simple and quick.
As to what exactly should makeCompatibleWith return: it's up to you. It can be a type that carries a reference, for example:
class MyClass
{
int a, b;
struct Internal
{
MyClass &val;
Internal(MyClass &val) : val(val) {}
MyClass &operator+=(const MyClass &o) noexcept {
val.b += o.b;
return val;
}
MyClass operator+(const MyClass &o) const noexcept {
return { val.a, val.b + o.b };
}
};
public:
MyClass() : a{}, b{} {}
MyClass(int a, int b) : a(a), b(b) {}
Internal makeCompatibleWith(const MyClass &o) noexcept {
thread_local static MyClass dummy;
assert(a == o.a);
if (a != o.a)
return { dummy };
return { *this };
}
};
Note that makeCompatibleWith would be undefined behavior when used from multiple threads if dummy wasn't thread-local.
I have two classes, lets call them A and B. And I overloaded operator+= in class A. Now I want to do something like this:
A += B + B + B
And class B doesn't have overloaded operator+, which is a problem because the evaluation is right to left (it wants to add all Bs and then += the result to A).
Is there any way to achieve my goal without actually overloading operator+ for class B?
Is there any way to achieve my goal without actually overloading operator+ for class B?
In a word, no.
A::operator+= takes a B as input, so if you want A += B + B + B to work, you need a way of adding B objects together to produce a new B that += can take as input, and that is exactly what operator+ is meant for.
This is possible.
Instead of overloading the addition operator, you can make B implicitly convertible to and from an arithmetic type. A demo that requires no overloading of operator+ for B as per requirement, yet allows the exact expression that you desire:
struct B {
B() = default;
// this constructor makes B convertible from int
B(int){}
// this operator makes B convertible to int
operator int() {
return 42;
}
};
struct A {
A& operator+=(const B&) {
return *this;
}
// alternative:
// if you use this, then B does not need to convert from int
// A& operator+=(int)
};
int main() {
A A;
B B;
A += B + B + B;
}
I have something like
struct Foo {
const double a;
const double b;
Foo(double c);
}
Foo::Foo(double c) {
double tmp = f(c);
a = g(tmp);
b = h(tmp);
}
where f,g,h are functions implemented elsewhere. This gives the expected "uninitialized const member" error.
I could fix it with
Foo::Foo(double c): a (g(f(c))), b (h(f(c))) {}
but f is an expensive function and I wouldn't like to run it twice.
My question is, how can I solve this problem without running f twice or making tmp a permanent member of Foo?
Typically, delegating constructors offer a simple solution to this type of problem. In this case you'll have to introduce some way to distinguish between the two constructors:
private:
// the int param is unused
Foo(double fc, int) : a(g(fc)), b(h(fc)) {}
public:
Foo(double c) : Foo(f(c), 0) {}
I define a global non-member method for + overloading
Like
ClassA operator+(const ClassA& a, const ClassB& b);
{
blah blah ;
}
In the communicative one, I can use
1)
ClassA operator+(const ClassB& b, const ClassA& a)
{
return operator+(a,b);
}
2)
ClassA operator+(const ClassB& b, const ClassA& a)
{
return a + b;
}
Any difference between 1 and 2?
Beyond the obvious difference pointed out first by #barakmanos in the comments ("the second one is more readable"), there is another technical difference.
Assume for a second, the following definitions:
struct B;
struct A
{
void operator+(B const&) const { ::std::cout << "member\n"; }
friend void operator+(A const&, B const&) { ::std::cout << "friend\n"; }
};
struct B { };
Now, consider the following three statements:
operator+(A(), B());
A().operator+(B());
A() + B();
The first one obviously calls the friend (free) function, the second one calls the member. However, the third one would call either if the other was not defined. In this special case, it cannot find a better match and would thus be ill formed. There are a few ways to modify this behaviour, e.g. if the member function was different in const-requirements, the expression could be correct and just lead to a larger overload set.
This demonstrates the difference in your two expressions: operator+(a,b) only considers free functions and not member functions overloading the binary plus operator.
In fact, the C++ standard has an example for another difference:
A() + B() only does argument dependent lookup, while operator+(A(), B()) does a normal function lookup. This means that the following is an error (taken from C++11 §13.3.1.2.10):
struct A { };
void operator + (A, A);
struct B {
void operator + (B);
void f ();
};
A a;
void B::f() {
operator+ (a,a); // error: global operator hidden by member
a + a; // OK: calls global operator+
}
Why do I get error: no match for ‘operator=’ in ‘y = x’ in the following code?
Cant the a-component of b not just be assigned to like it was a-object = a-object?
struct a {int i;};
struct b : public a {int j;};
int main()
{
a x;
b y;
x.i = 9;
y.j = 5;
y = x; // error: no match for ‘operator=’ in ‘y = x’
// expected: y.i = 9
return 0;
}
You are not explicitly defining any assignment operators, so the compiler will generate its own default operators for each struct. The compiler's default assignment operator in b takes a b as input and will assign both members. And assignment operators are not automatically inherited when using inheritance. That is why you cannot pass an a to a b - there is no assignment operator in b that takes an a as input. If you want to allow that, you need to tell the compiler as much, eg:
struct a
{
int i;
a& operator=(const a &rhs)
{
i = rhs.i;
return *this;
}
};
struct b : public a
{
int j;
using a::operator=;
b& operator=(const b &rhs)
{
*this = static_cast<const a&>(rhs);
j = rhs.j;
return *this;
}
};
int main()
{
a x;
b y;
b z;
...
y = x; // OK now
y = z; // OK as well
...
return 0;
}
No, because even if the classes are related they are different types.
Think about this, even if it was allowed and it would work like you expected, what would the value of y.j be after the assignment?
As the error states, you need to implement an assignment operator. That is, a function that tells your program how to assign one object to another one. You can find plenty of information on it if you search the web, e.g. on http://www.cplusplus.com/articles/y8hv0pDG/