assignment operator overloading in c++
There are no problems with the second version of the assignment operator. In fact, that is the standard way for an assignment operator.
Edit: Note that I am referring to the return type of the assignment operator, not to the implementation itself. As has been pointed out in comments, the implementation itself is another issue. See here.
overloading assignment operator and header file in c++
You need to declare the function in your header file so you can define it later on.
using namespace std;
#include <stdlib.h>
#include <string>
#include <iostream>
#include "Chemical.h"
class Cabinet{
private:
int rows;
int id_cabinet;
int columns;
Chemical*** chemicals;
string alphabet [9];
public:
Cabinet(int id = 0, int rows = 0, int columns = 0);
Cabinet& operator=( const Cabinet& right );
~Cabinet();
int getRow();
int getColumn();
int plusCount();
};
C++ overload assignment operator
The line SpecialFloat f = 1.0f;
cannot perform assignment from 1.0f
to f
because f
doesn't exist yet. We are just creating it.
It would do if you had written SpecialFloat f{0.0f}; f = 1.0f
[Demo].
The line SpecialFloat f = 1.0f;
is doing copy initialization (1).
Initializes an object from another object.
Syntax
T object = other; (1)
In your code T
is SpecialFloat
, a class type, and other
is a float
(not T
or derived from T
).
The effects of copy initialization are:
...
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T [...] user-defined conversion sequences that can convert from the type of other to T are
examined and the best one is selected through overload resolution. The result of the conversion, which is a rvalue temporary [...] of the cv-unqualified version of T if a converting constructor was used, is then used to direct-initialize the object.
User-defined conversions from float
to SpecialFloat
should be examined. However, explicit constructors are not considered for copy-initialization.
Notes
Copy-initialization is less permissive than
direct-initialization: explicit constructors are not converting
constructors and are not considered for copy-initialization.
One way to solve this is to use direct initialization, and, if possible, with braces instead of parentheses, i.e. SpecialFloat f{1.0f};
[Demo].
There's a C++ Core Guideline advising about preferring the {}-initializer syntax.
Also, declaring single-argument constructors explicit is a general recommendation, so I would keep the user-declared constructor as explicit.
Another way would be to make SpecialFloat
class an aggregate, by removing the user-declared constructor, and use aggregate initialization, SpecialFloat f = {1.0f};
[Demo].
Finally, as commented by others, notice the signature of the assignment operator is SpecialFloat& operator=(const float f)
, what indicates that a SpecialFloat&
has to be returned. So first, update the object with m_float = f;
; then, return it with return *this;
.
[Edit]
I just came accross this article from Arthur O'Dwyer's, The Knightmare of Initialization in C++ where he basically favours copy initialization over direct initialization with braces, in order to improve the readability of the code.
Simple guidelines for variable initialization in C++:
- Use = whenever you can.
- Use initializer-list syntax {} only for element initializers (of containers and aggregates).
- Use function-call syntax () to call a constructor, viewed as an object-factory.
Thus:
int i = 0;
std::vector<int> v = {1, 2, 3, 4};
Widget w(name, price, quantity);
Moreover, he suggests to combine the copy initialization with the Almost Always Auto style. Going back to the original OP's question, that would allow us to keep the SpecialFloat
class untouched and write auto f = SpecialFloat{1.0f};
[Demo].
He acknowledges though that his guidelines conflict with the aforementioned C++ Core Guideline of preferring the {}-initializer syntax.
overloading copy assignment operator with classes without a reference parameter name
How does this copy assignment operator work?
Redacted:
Base& operator=(Base const& rhs) {
cout << "Base operator=\n";
value = rhs.value;
return *this;
}
The assignment operator is just a function call. In this particular class's case, the compiler will synthesize one that does the right thing, but if you want the cout
side-effect for educational purposes you've done the right thing.
You could also call it in a method function style:
b.operator=(b1);
The b = b1;
is just syntactic sugar for the above.
The assignment operator should be self-assignment safe. But general guidance is to make it safe without checking for the self-assignment case explicitly, which is "bad" because it optimizes for the pathological case.
In your implementation, it is safe without the self-assignment check.
I prefer specifying the qualifier in Base const&
order rather than const Base&
order, because the general rule is "the qualifier always binds to the thing to its immediate left", and the exception to the general rule is "...unless the qualifier comes first, in which case it then binds to the thing to its immediate right." That becomes a problem when people have the grasped the exception to the rule, but not the general rule, and then have troubles parsing Base*const*
in their heads.
Does the reference before the operator keyword need a parameter name?
It's name is *this
. It is a return type, not a parameter, so it does not have a parameter name.
Some people have troubles with "Why does C++ use this
as a pointer to itself, rather than as a reference to itself."
It is a historical anomaly from the evolution of C++. Originally, there was a this
pointer, and references had not been added to the language yet.
With 20/20 hindsight, this
would have been a reference. But that ship has sailed.
In my own code, only to help make it more legible, I'll do:
auto& self = *this;
self[i] = 5;
...rather than the more confusing (imo)...
(*this)[i] = 5;
Overloading assignment operator in C++
Not returning a reference is a waste of resources and a yields a weird design. Why do you want to do a copy for all users of your operator even if almost all of them will discard that value?
a = b; // huh, why does this create an unnecessary copy?
In addition, it would be surprising to users of your class, since the built-in assignment operator doesn't copy likewise
int &a = (some_int = 0); // works
Overload assignment operator and rule of zero
According to my understanding, adding a operator=
overload will not prevent the compiler from generating the default one according to the rule of 0.
I base this understanding on the fact that your operator=
overload is not in fact a copy assignment, nor a move assignment.
Therefore the rules about generaing default constructors and assignment operators are not relevant.
I verified it with MSVC.
You can use the code below to verify with your compiler:
#include <iostream>
template <typename T>
struct B
{
B(T const & n) : bn(n) {}
T bn{ 0 };
};
template <typename T>
struct A
{
A(T const & n) : an(n) {}
A<T>& operator=(const B<T>& rhs)
{
an = rhs.bn;
return *this;
}
T an{ 0 };
};
int main()
{
A<int> a1{ 5 };
A<int> a2{ 6 };
std::cout << a2.an << ",";
a2 = a1; // Use default assinment
std::cout << a2.an << ",";
B<int> b{ 3 };
a2 = b; // Use custom assignment
std::cout << a2.an << std::endl;
return 0;
}
The output should be: 6,5,3:
6 is the value A<int> a2
is constructed with, 5 is the value assigned from A<int> a1
, and 3 is the value assigned from B<int> b
.
Note: an alternative would be to use a user-defined conversion function, as @LouisGo commented (see above).
Overloading copy assignment operator in c++
Type b = a;
is not assignment. Is is a variable definition with initialization and causes the copy constructor of Type
to be called with a
as argument. Constructors don't have return values and as you correctly note it wouldn't make sense for Type b = a
to have any result value, because it isn't even an expression.
However
b = a;
(with prior Type B;
) is assignment. Assignment is an expression, so it has a result value that can be used in other expressions. For example the following is valid:
int a = 0;
(a = 2) += 1;
and will set a
to 3
. Here for fundamental types such as int
, the assignment returns a reference to the left-hand side of the assignment.
With class types this is mimicked by having the copy assignment operator return a reference to the left-hand side of the assignment (i.e. *this
) as well.
One typical use case for this is assigning to multiple instances:
Type a, b, c;
// Do something with c
a = b = c;
After the last line all three a
, b
and c
will be in the same state, that of c
prior to the change assignment, because the expression is parsed as a = (b = c);
and the right-hand assignment returns a reference to b
which is used to assign to a
after c
was assigned to b
.
It is not required to return a reference to *this
from an overloaded assignment operator. Doing is convention however, because it enables this particular use case. If you do not return a reference to *this
users of your class may be surprised when that idiom suddenly doesn't work for your class, even if it may not be often used.
A value returned from a function (or operator) does not need to be used. If you write
b = a;
the returned reference is simply discarded. It is never stored anywhere and that is not a problem at all.
c++ overloading assignment operator of another class
If you want the ability to assign a double
to fraction
you can declare a non-explicit constructor:
fraction(double d = 0, double n = 1) : d(d), n(n) {}
and for reverse
operator double() const { return n/d; }
and then
fraction f;
f = 12.5; // Assign a double to fraction
double x = f; // Assign fraction as double to a double
Purpose of assignment operator overloading in C++
Actually, after seeing juanchopanza's answer (which was deleted), I think I ended up figuring it out myself.
Copy-assignment operators allow classes like basic_string
to avoid allocating resources unnecessarily when they can re-use them (in this case, memory).
So when you assign to a basic_string
, an overloaded copy assignment operator would avoid allocating memory, and would just copy the string data directly to the existing buffer.
If the object had to be destroyed and constructed again, the buffer would have to be reallocated, which would be potentially much more costly for a small string.
(Note that vector
could benefit from this too, but only if it knew that the elements' copy constructors would never throw exceptions. Otherwise it would need to maintain its exception safety and actually perform a copy-and-swap.)
Related Topics
How to Run Application Which Requires Admin Rights from One That Doesn't Have Them
Why Are Bitwise Shifts (<< and >>) Used for Cout and Cin
Is It Legal to Use the Increment Operator in a C++ Function Call
Xxxxxx.Exe Is Not a Valid Win32 Application
What Std::Locale Names Are Available on Common Windows Compilers
Inserting into an Unordered_Set with Custom Hash Function
Differencebetween the /Ox and /O2 Compiler Options
Why Does C++11 Have 'Make_Shared' But Not 'Make_Unique'
How to Print Utf-8 Strings to Std::Cout on Windows
How Do Take a Screenshot Correctly with Xlib
Translating Python Dictionary to C++
Convert a Single Color with Cvtcolor
Loop Until Integer Input Is in Required Range Fails to Work with Non-Digit Character Inputs
Double Delete in Initializer_List VS 2013