Reputation: 171
I am looking to overload, let's say, the addition operator and have it add two objects of the same class. When I declare this "operator+" prototype function in the class declaration in the header file, I pass in both objects as parameters. I get a compiler error saying that "binary 'operator +' has too many parameters". I was searching around for an answer online and found out that declaring an inline function just outside the class declaration in the header file compiled out. I'm wondering what I was doing wrong or if I'm missing something here. Here is the code I am using in the header file.
class Person
{
private:
int age;
double weight;
public:
Person::Person(); //default constructor
Person::~Person(); //default desctructor
Person operator+(Person r, Person i);
};
This compiles with the error I mentioned above. Below is the code that compiles fine.
class Person
{
private:
int age;
double weight;
public:
Person::Person(); //default constructor
Person::~Person(); //default desctructor
};
inline Person operator+(Person r, Person i)
{
return Person(0,0);
}
Upvotes: 3
Views: 4218
Reputation: 1335
class Person
{
private:
int age;
double weight;
public:
Person(); //default constructor
~Person(); // destructor
Person operator+(const Person &r); //overloaded operator as member function, so only one argument is required to be passed
};
Implementation :
Person Person::operator+(const Person &r)
{
Person x;
x.age=this->age + r.age; // this refers to the object on which the function has been invoked, P1 in this case(see below)
return x;
}
When you overload a binary operator(+ in this case) as member function, the object on which the operator is invoked is passed implicitly to the function and you need to pass only one argument explicitly
Thus your main function should be like this
int main()
{
Person P1,P2;
P2=P1+P2; //P1 is passed implicitly
//The above expression is equivalent to P2=P1.operator+(P2);
}
Upvotes: 0
Reputation: 26
I agree with argumentations of agsamek and sbi. I add some extra considerations
Next follow my solution to your question:
class Person
{
private:
int age;
double weight;
public:
Person(){} //default constructor
Person(int a, double w) : age(a), weight(w) {}
~Person(){} //default desctructor
int getAge() const { return age; }
double getWeight() const { return weight; }
const Person & operator =(const Person & rha) {
age = rha.age; weight = rha.weight; return *this;
}
};
Person operator +(const Person & lha, const Person & rha)
{
return Person(lha.getAge() + rha.getAge(), rha.getWeight() + lha.getAge());
}
int _tmain(int argc, _TCHAR* argv[])
{
Person p1(30,75);
Person p2(40,80);
Person sumOfPis = p1 + p2; // <-- Without "operator =" this statement will use the default copy constructor
return 0;
}
Upvotes: 0
Reputation: 299790
I only have one advise: use Boost.Operators.
class Person: boost::addable<Person> // yes private inheritance
{
public:
Person& operator+=(Person const& rhs);
private:
};
There are 2 advantages as far as I can see:
addable
is pretty much self-explanatoryBoost.Operators provides a reference table, which for each behavior lists the required operators that should be defined and those that will be generated automatically.
It's very handy to keep the interface compact and to inject some documentation right into the code.
Upvotes: 1
Reputation: 9054
If you declare oparator+
as an instance function then the first argument is being passed as this
object and thus you need only one more argument. Read this for more info, in particular try to understand the const
concept:
http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html
The best approach as advised in the referenced artice is:
class Person
{
...
Person &operator+=(const Person &i);
const Person operator+(const Person &i) const;
...
};
Person &Person::operator+=(const Person &i) {
... // Do the compound assignment work.
return *this;
}
const Person Person::operator+(const Person &i) const {
Person result = *this; // Make a copy of myself. Same as MyClass result(*this);
result += i; // Use += to add other to the copy.
return result; // All done!
}
if you decide to use const
version remember that you will only be able to call const
methods on this
and i
references. This is the preferred way.
The article I referenced to explains the idea of overloading +=
first and then defining +
using +=
in more details. This is a good idea since +=
operator must be separately overloaded.
Additionally - David Rodríguez suggests operator+
to be implemented as a free function regardless of the presence of += .
Upvotes: 8
Reputation: 40558
From what I've read the best practice is to declare operator+
as a friend function and not as a member function.
There's a whole discussion of this issue over at cplusplus.com:
Binary operators as friends - why?
Meyers also discusses it in his book Effective C++ IIRC.
Quoting from the comment of geustgulkan:
For any given binary operator, it the left hand object that carries out the operation.
Say we have a class ClassX which has an overload for the + operator for integers. Then if we create an object of thet class (call it objx), then we can say objx + 2. objx will will carry out the operation and return the result object of ClassX.
But what happens if we say 2 + objx ? The result should be the same as 2 + objx - BUT integers are not classes and certainly numeric literals are not - so 2+objx is not possible directly.
It would be a pain if we had to design our code to make sure we always has ojbjects of ClassX on the left hand side of the + whenever we wanted to add an int to it.
This is where we use friend overloads for operator+ for ClassX.
class ClassX
{
friend ClassX operator+(ClassX objx, int i);
friend ClassX operator+(int i, ClassX objx);
};
So what you probably want is:
class Person
{
private:
int age;
double weight;
public:
Person::Person(); //default constructor
Person::~Person(); //default desctructor
friend Person operator+(const Person &rhs, const Person &lhs);
};
Person operator+(const Person &lhs, const Person &rhs) {
// do whatever constitutes addition here
Person temp = lhs;
temp.weight += rhs.weight;
return temp; // return copy of temp
}
Upvotes: 1
Reputation: 224059
Every member function has an implicit first argument: this
. This is also true for operators. Therefor, if you want to make operator+()
a member, it must only take one argument, the right operand, because the left operand already is this
.
However, for binary operators that can be either a member function or a free function, my rule of thumb is to make those a free function which treat their arguments symmetrically (operator+()
doesn't change either of its operands), and make those a member function which don't (operator+=()
changes its left operand, but not its right).
Further, for all arithmetical operators, there's a nice pattern to implement them based on their combined assignment versions. That is, operator+()
would be based on operator+=()
, -
based on -=
etc.
Add to this that you don't want to needlessly copy class objects, but usually want them to be passed per const
reference.
Based on this, my canonical versions of operator+
would be:
class Person
{
public:
Person& operator+=(const Person& i)
{
// whatever
return *this;
}
};
inline Person operator+(Person lhs, const Person& rhs)
{
lhs += rhs; // note: lhs passed per copy
return lhs;
}
However. What's probably the most important rule of thumb regarding operator overloading is this: Don't do it. This might sound paradoxical, but most often named functions are a lot better than operators, because the latter make the code less readable than normal functions would. And when writing code, readability should be the most important aspect. Unless an operators has a clear and undisputed meaning in the application domain, don't overload it for a class.
In your example there certainly is no clean and undisputed meaning of operator +
applied to two persons. What does it mean in the real world to add to persons? (The first meaning I could think of wouldn't have a single person as a result, but an array of persons.:)
)
So, unless overloading this operator for your Person
class is a homework assignment, I would strongly advice against it. (And if it is an assignment, I'd blame the teacher for finding such a bad example.)
Upvotes: 6
Reputation: 3666
Here is an example for a working += in a class.
Vector3D& operator+=( const Vector3D& other ) {
x+=other.x;
y+=other.y;
z+=other.z;
return *this;
}
Upvotes: 2
Reputation: 16129
Seems you made the member operator+ declaration with no intent to reference any Person-instance data: the member operator, as any member method, accepts the instance on which it is invoked as an argument.
If for some reason you need to make it a member (e.g., access to private state), you can declare it static.
Upvotes: 0