Overloading + problems in complex expressions
I have a class that represents 3D vectors. It has several member functions (dot product, cross product, etc.) as well as several overloaded operators (+ - * /). I am having problems using these operators in complex expressions.
In a simplified test case, if I overload the operator as
testclass operator+ (testclass& a, testclass& b) {
return testclass(a.get()+b.get());
}
I can do
testclass a = testclass(3);
testclass b = testclass(4);
testclass c = a + b;
no problem, however more complex expression
testclass c = a + b + a + b;
won't compile. I can fix the problem by changing the overload function to
testclass operator+ (testclass a, testclass b) {
return testclass(a.get()+b.get());
}
however, this involves passing by value, which I understand is slower than the referencing scheme in the first case. I use this class for a piece of math intensive code, and my actual class contains three long doubles as data items, so I suspect the performance impact can be significant.
My questions:
- Why is this behavior happening?
- Can I avoid this without resorting to passing by value?
- Passing by value rather than by reference affects performance anyway when I have three long doubles as data items? Will the optimizing compiler (g ++ -O3) optimize it?
Thanks everyone in advance.
Exact compilation error:
operator_overload.cpp: In function ‘int main()’:
operator_overload.cpp:37:29: error: no match for ‘operator+’ (operand types are ‘testclass’ and ‘testclass’)
testclass c = a + b + a + b;
^
operator_overload.cpp:37:29: note: candidate is:
operator_overload.cpp:30:15: note: testclass operator+(testclass&, testclass&)
testclass operator+ (testclass& a, testclass& b) {
^
operator_overload.cpp:30:15: note: no known conversion for argument 1 from ‘testclass’ to ‘testclass&’
My complete test code looks like this:
#include <iostream>
class testclass {
public:
testclass();
testclass(int);
int get();
void set(int);
private:
int data;
};
testclass::testclass() {
data = 0;
}
testclass::testclass(int a) {
data = a;
}
int testclass::get() {
return data;
}
void testclass::set(int a) {
data = a;
return;
}
testclass operator+ (testclass& a, testclass& b) {
return testclass(a.get()+b.get());
}
int main () {
testclass a = testclass(3);
testclass b = testclass(4);
testclass c = a + b + a + b;
std::cout << c.get() << std::endl;
return 0;
}
source to share
The problem is that rvalues cannot be bound to lvalue references. Intermediate results in a + b + a + b
, say a+b
, are temporary and the full expression does not work. OTOH, const references can bind to rvalues. Change the signature to testclass operator+ (const testclass& a, const testclass& b)
to resolve this issue.
For the above signature to make sense, you also need to have a testclass::get
method const
.
source to share
You need to use const constructors to hold ref to rvalue
code:
#include <iostream>
class testclass {
public:
testclass();
testclass(int);
int get() const;
void set(int);
private:
int data;
};
testclass::testclass() {
data = 0;
}
testclass::testclass(int a) {
data = a;
}
int testclass::get() const {
return data;
}
void testclass::set(int a){
data = a;
return;
}
testclass operator+ (const testclass& a, const testclass& b) {
return testclass(a.get()+b.get());
}
int main () {
testclass a = testclass(3);
testclass b = testclass(4);
testclass c = a + b + a + b;
std::cout << c.get() << std::endl;
return 0;
}
works for me, gcc 4.9.2
source to share