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+
}
Related
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 implemented two classes (parent and derived) comparison operator, but testing it I have noticed a confusing behavior in case of using pointers. In addition, I have some other questions about good practices.
Here it is the code:
struct A
{
int getN() { return _n; }
virtual bool equals(A &other) {
return getN() == other.getN();
}
friend bool operator==(const A &one, const A &other);
A(int n) : _n(n) { }
private:
int _n;
};
bool operator==(const A &one, const A &other) {
return one._n == other._n;
}
struct B : public A
{
friend bool operator==(const B &one, const B &other);
B(int n, int m = 0) : A(n), _m(m) { }
private:
int _m;
};
bool operator==(const B &one, const B &other) {
if( operator==(static_cast<const A&>(one), static_cast<const A&>(other)) ){
return one._m == other._m;
} else {
return false;
}
}
int main()
{
A a(10), a2(10);
B b(10, 20), b2(10, 20), b3(10, 30);
A *a3 = new B(10, 20);
bool x1 = a == a2; // calls A operator (1)
bool x2 = b == b2; // calls B operator (2)
bool x3 = a == b; // calls A operator (3)
bool x4 = b == a; // calls A operator (4)
bool x5 = b == *a3; // calls A operator (5)
bool x6 = a == b3; // calls A operator (6)
bool x7 = b3 == a; // calls A operator (7)
return 0;
}
Questions
Comparing A instances with B ones, the A class operator is called, is this the correct behavior?
The point 5 is the one that seems confusing to me. a3 is declared as A but instanced as B, but the class A operator is called. Is there any way to solve this?
If the operator was implemented as a instance method, depending on it is called with an A object or a B one, the executed method is different. For example:
a == b // executes A::operator==
b == a // executes B::operator==
I assume that this is confusing and error prone, and must be avoided. Am I right?
Comparing A instances with B ones, the A class operator is called, is this the correct behavior?
Yes, because this is the only applicable overload.
If the operator was implemented as a instance method, depending on it is called with an A object or a B one, the executed method is different. [...] I assume that this is confusing and error prone, and must be avoided.
Right, this is not a good idea, because equality operator must be symmetric. Although it is possible to implement it symmetrically with two separate operators, it introduces a maintenance liability in the code.
One approach to solve this is to expan your equals member function, and have each subclass implement equality for its own type:
struct A {
int getN() const { return _n; }
virtual bool equals(A &other) const {
return getN() == other.getN();
}
friend bool operator==(const A &one, const A &other);
A(int n) : _n(n) { }
private:
int _n;
};
struct B : public A
{
B(int n, int m = 0) : A(n), _m(m) { }
virtual bool equals(B &other) const {
return A::equals(*this, other) && _m == other._m;
}
private:
int _m;
};
bool operator==(const A &one, const A &other) {
return typeid(one)==typeid(two) && one.equals(two);
}
"At the heart" of this implementation is typeid operator, which lets you check for type equality at run-time. The virtual call to one.equals(two) happens only if the types of one and two are exactly the same.
This approach puts responsibility for equality comparison with the class itself. In other words, each class needs to know how to compare its own instances, and optionally rely on its base for comparison of its state.
Comparing A instances with B ones, the A class operator is called, is
this the correct behavior?
B& can be converted to const A& but A& can't be converted to const B&. So comparing a == b there's really only one choice.
"Class operators" isn't a thing. In your code you've implemented operator== as non-member functions, that you've also made friends of A and B.
The point 5 is the one that seems confusing to me. a3 is declared as A
but instanced as B, but the class A operator is called. Is there any
way to solve this?
Dereferencing a3 returns A&, not B&.
If the operator was implemented as a instance method, depending on it
is called with an A object or a B one, the executed method is
different. For example:
a == b // executes A::operator==
b == a // executes B::operator==
I assume that this is confusing and error prone, and must be avoided. Am
I right?
If operator== is implemented as an instance method it's called on the left hand operand. In the first case it's a, in the second it's b. So b == a is only valid if you've implemented bool B::operator==(const A&).
Comparing A instances with B ones, the A class operator is called, is this the correct behavior?
Since you do not have any virtual functions in A you only deal with function overloading which means that compiler decides which function to call at compile time. As B publicly inherited from A, pointer or reference to B can be implicitly converted to A but not vice versa. In this case it means "unless both arguments are B only first resolution would be called". Note when you dereference a pointer only type of pointer matters to determine type at compile time, so if A *pointer points to instance of A or B does not matter in this case at all, *pointer always has type A.
If you want functions to be called based on actual type you need to use virtual functions, details on how to do that for operator== can be found here implementing operator== when using inheritance
I have this class definition:
class foo{
public:
foo();
foo(const int& var);
foo(const foo& var);
~foo();
const foo operator +(const foo& secondOp) const;
private:
int a;
//plus other values, pointers, e.t.c.
};
Also I have made this implementation for '+' operator overloading:
const foo foo::operator +(const foo& secondOp) const{
//I want here to check if i have one operand or two...
if ((FIRST_OPERAND.a!=0) && (secondOp.a==0)){
cout << "ERROR, second operand is zero";
return FIRST_OPERAND;
}
else if ((FIRST_OPERAND.a==0) && (secondOp.a!=0)){
cout << "ERROR, first operand is zero";
return secondOp;
}
}
When i write in main():
foo a(2);
foo b;
foo c;
//I want here to print the ERROR and
//return only the values of a
c = a + b;
Ηow can i return the value of the first operand if the second operand is zero and vice versa?
You're almost there. Since it's a member function, the first operand is *this, so replace FIRST_OPERAND.a with this->a or just a.
However, it might be better to make it a non-member function to allow conversions on both operands (i.e. to be able to write a + 2 or 2 + a). It will need to be a friend in order to access the private member(s).
friend foo operator +(const foo& firstOp, const foo& secondOp);
Also, it's best not to return a const value as that prevents moving from the return value.
It is the compiler that checks the syntaxical correctness of the program. It is unable to distinguish whether you indeed wanted to write
c = a;
that is to do the assignment or you wanted to write
c = a + b;
The both statements are correct.
It is a so-called logical error. The compiler is unable to see what we thoght.
For your line c = a; The assignment operator is implemented by the compiler (just shallow copying the object memory).
That is the reason your code compiles "without the second operand".
If you wish to disallow using the assignment operator - hide it. E.g. by implementing with the private access modifier.
You have to define this function as a friend function
friend Int operator + (int first, Int &second);
this function can perform obj + 2 or 2 + obj.
Int operator + (int first, Int& second){
second.a += first;
return second;
}
Let's say we have this class A:
class A
{
public:
int a;
A(int b)
{
a = b;
}
};
I would like to create a + overload such that I could use it like this
A a(1),b(2),c(3),&d;
d = a + b + c;
without modifying the content of each object. The next logical thing would be allocating a new chunk of memory each time like this:
A &operator+ (const A &b)
{
A *c = new A(a+b.a);
return *c;
}
But this would create a new problem: intermediate results are lost, causing memory leaks.
I could have easily solved this problem by making a static function that takes three A object references and stores the sum of the first two in the third, but I'm willing to bet that there must be some way to make + overload happen the way I want.
So the question is: is there any way I could use a chain of operator overloads that do not modify the operands without causing memory leaks?
You can simply use pass by value and do this:
A operator+ (A other) //pass by value
{
other.a += a;
return other;
}
Or, since the member a is publicly accessible, you can (rather should) make operator+ a non-member function as:
A operator+(A left, A const &right)
{
left.a += right.a;
return left;
}
Notice that the first argument is accepted by value, and second by reference. In this way, you don't need to declare a local variable in the function. You can use the first parameter; after all it is local to the function, you can do whatever you want to do with it: in this case, we just add right.a to it, and return it.
A better design of class would be this: (read the comments)
class A
{
int a; //make it private
public:
A(int b) : a(b) //use member initialization list
{
}
A& operator+=(A const & other) //add `+=` overload, as member of the class
{
a += other.a;
return *this;
}
};
//and make `+` non-member and non-friend
A operator+(A left, A const & right)
{
left += right; //compute this in terms of `+=` which is a member function
return left;
}
There is no need to use pointers inside operator+. You can allocate the intermediate object in the stack and then return it:
A operator+ (const A &b)
{
A c(a+b.a);
return c;
}
Or just:
A operator+ (const A &b)
{
return A(a+b.a);
}
Or even simpler:
A operator+ (const A &b)
{
return a+b.a;
}
Since this implicitly calls A::A(int).
Note that I removed the reference from the return type. You can't return a non-const reference to a local.
Then you would use it this way:
A a(1),b(2),c(3),d;
d = a + b + c;
Note that d is no longer a reference.
template<class Y>
operator auto_ptr_ref<Y>() throw() {
return auto_ptr_ref<Y>(release());
}
It is part of implementation of class auto_ptr in standard library.
What does this means to do?
Why there is an "auto_ptr_ref" between "operator" and "()"?
I'll tell you why that conversion operator happens to be there. Well, look at this example:
struct A;
struct B {
explicit B(A&a):a(a){ }
A &a;
};
struct A {
A() { }
A(B b){ move_from(a); }
A(A &a) { move_from(a); }
operator B() { return B(*this); }
void move_from(A &a) {
std::cout << "A::A(#" << &b.a << ")" << std::endl;
}
};
int main() {
A a = A();
}
We have move semantics for our class A: In its copy constructor, we want to "steal" away some stuff from the other instance. For auto_ptr, that is the pointer that is managed, for us we just output a message instead. What is important is that we can't use a usual copy constructor:
A(A const& a) {
/* oops, a is const, we can't steal something from it! */
}
But if we change that to A(A &a), we won't be able to construct from a by-value/temporary A: Those can't be bound to a reference-to-nonconst:
A(A &a) {
}
...
A a = A(); // fail, because A &a = A() doesn't work
auto_ptr and our A class uses the trick that non-const member functions can still be called on temporaries/by-value A's. That is, we could also have written:
struct A {
...
B get_b() { return B(*this); }
...
};
...
A a = A().get_b();
But that works, we don't want to be bothered with that, of course. We want that it just works to assign a A() or the return value of a function returning an A by-value. So what auto_ptr and our A class uses is a conversion operator, which automatically figures out that when A is converted to B, then we could construct a A instance using the B we created temporarily.
That is the conversion operator in action, casting from auto_ptr to auto_ptr_ref<Y>.