Reputation: 900
I wonder in c++ about the operator overloading forms of the below like:
ClassName & operator+(ClassName &other)
ClassName operator+(ClassName &other)
Classname operator+(const ClassName &other)
Classname operator+(const Classname other)
Classname operator+(Classname other)
What are the difference of usage ??
Upvotes: 0
Views: 109
Reputation: 153830
Just for reference: none of the quoted operators is the one normally
actually overloaded! The one which is normally overloaded is more like
this (assuming it is in the same namespace as ClassName
):
ClassName operator+ (ClassName const& op1, ClassName const& op2) {
ClassName rc(op1);
rc += op2;
return rc;
}
There are some variations how this operator can be implemented. In
particular the first argument may be passed by value to avoid the copy
in the implementation: in some cases the copy could be elided. This particular implementation using a named variable and returning it by name is intended to enable copy elision (as @juanchopanza pointed out, return ClassName(op1) += op2;
isn't allowed to elide the copy for the return value).
With respect to your actual question, it is important to distinguish between references and values:
When a value like ClassName
is used, the object being passed to a
function or returned from a function is a copy. When the class
in question is trivial, that is just OK but if the class is more
complicated and allocates memory for its members there may be some
cost in creating actual copies. On the other hand, semantically it is
often necessary to use a copy. For example, the result of an addition
is normally a different object and, thus, needs to be a copy.
To take the edge out of the some of the costs, the compiler tries hard to avoid copies when it can. For example, when returning a local variable the copy is in many cases elided or the object is, at least, moved (assuming C++11 or later is used and the class has a move constructor).
When a reference like ClassName&
or ClassName const&
is used,
the entity is actually just a name for an object. No copy is made
but an object needs to exist somewhere. The presence of const
vs.
the absence of const
just indicates whether all methods or only
const
methods can be called or whether a reference can be passed
where another reference is needed: a non-const
reference can
be converted to a const
reference but not vice verse.
For the purpose of parameters, the key difference between const
reference and non-const
reference is that temporary objects
cannot bind to non-const
reference while they can bind to
const
references.
With that sorted, here is a run-through of the different declarations of
the operator+()
:
ClassName & operator+(ClassName &other)
This declaration takes a non-const
reference as argument and returns
a non-const
reference. For the argument this means that it can't
be a temporary but rather needs to have a name. For the return that
means that the returned object needs to be kept alive. Normally the
addition creates a new object and trying to keep an object alive
is bound to not work. If ClassName
is really expensive to copy
you might not want to provide an operator+()
but rather just
an operatr+=()
which semantically produces the same result as
operator+()
but does so in-place.
ClassName operator+(ClassName &other)
This declaration has the primary constraint that the argument is
a non-const
reference, i.e., the argument cannot be a temporary
object but has to be an lvalue, i.e., something which is somehow
named. However, the arguemnt won't be copied.
ClassName operator+(const ClassName &other)
This declaration works with temporaries and is one of the two likely
candidates of how a member operator+()
would look like. The argument
still isn't copied but because it is [logically] immutable temporary
objects can be used as arguments.
ClassName operator+(const ClassName other)
This will copy the argument. For the purpose of the declaration
the const
will be meaningless and it can actually differ between
different declarations of the same function. When the definition
uses this declaration it means that the argument is copied, i.e., the
operator+()
has a local version but it can't actually change this
copy. Most likely it will need to create another copy to produce a
result. Correspondingly, I think defining a function with a const
value argument is utterly pointless: if you want a constant, use
const ClassName&
or ClassName const&
(these are identical; I do
prefer the latter notation as it results in consistent placement).
ClassName operator+(ClassName other)
Like the previous declaration this one copies the argument but the
argument is mutable. Assuming the oepration is commutative, you can
readily mutate other
to produce the return value. Note, however,
that copying other
won't be elided (the compiler is not allowed
to elide copying function parameters) but it can be moved. Assuming
ClassName
is either cheap to copy or other
is used as the basis
for the result, this is the other likely candidate how the operator
is defined.
Upvotes: 3
Reputation: 1091
First one returns a reference, and takes a reference - this means that you can theoretically change both arguments, and you return a reference, which can be changed too. This is usually not what you want to do( 2 + 3 doesn't return 5 that can be reassigned to 17).
Second one is the same, but no reference returned.
Third has const reference - a reference which can't be modified. This is usually what you want to do, since you get element fast(you get the element), but you can't change it(incidentally or not).
Fourth one is like a third, but you copy an argument, and make it const for some reason. This makes little sense.
And the last one just takes a copy.
There isn't much difference between some of them - some of them make little sense if you think about what operator+
has to do; the area where they differ is mostly how you get the argument - and most of the time, you want to get it fast, so const ClassName& other
is probably your best bet.
Upvotes: 1