Reputation: 1290
I'm trying to understand how the copy assignment constructor works in c++. I've only worked with java so i'm really out of my waters here. I've read and seen that it's a good practice to return a reference but i don't get how i should do that. I wrote this small program to test the concept:
main.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main() {
Test t1,t2;
t1.setAge(10);
t1.setId('a');
t2.setAge(20);
t2.setId('b');
cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";
t2 = t1; // calls assignment operator, same as t2.operator=(t1)
cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";
Test t3 = t1; // copy constr, same as Test t3(t1)
cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";
return 1;
}
test.h:
class Test {
int age;
char id;
public:
Test(){};
Test(const Test& t); // copy
Test& operator=(const Test& obj); // copy assign
~Test();
void setAge(int a);
void setId(char i);
int getAge() const {return age;};
char getID() const {return id;};
};
test.cpp:
#include "test.h"
void Test::setAge(int a) {
age = a;
}
void Test::setId(char i) {
id = i;
}
Test::Test(const Test& t) {
age = t.getAge();
id = t.getID();
}
Test& Test::operator=(const Test& t) {
}
Test::~Test() {};
I can't seem to understand what i should be putting inside operator=()
. I've seen people returning *this
but that from what i read is just a reference to the object itself (on the left of the =
), right? I then thought about returning a copy of the const Test& t
object but then there would be no point to using this constructor right? What do i return and why?
Upvotes: 4
Views: 812
Reputation: 15446
We return a reference from the assignment operator so we can do some cool tricks like @SomeWittyUsername shows.
The object we want to return a reference to is the one who the operator is being called on, or this
. So--like you've heard--you'll want to return *this
.
So your assignment operator will probably look like:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
You may note that this looks strikingly similar to your copy-constructor. In more complicated classes, the assignment operator will do all the work of the copy-constructor, but in addition it'll have to safely remove any values the class was already storing.
Since this is a pretty simple class, we have nothing we need to safely remove. We can just re-assign both of the members. So this will be almost exactly the same as the copy-constructor.
Which means that we can actually simplify your constructor to just use the operator!
Test::Test(const Test& t) {
*this = t;
}
Again, while this works for your simple class, in production code with more complicated classes, we'll usually want to use initialization lists for our constructors (read here for more):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
Upvotes: 2
Reputation: 206667
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
Add
return *this;
as the last line in the function.
Test& Test::operator=(const Test& t) {
...
return *this;
}
As to the question of why you should return *this
, the answer is that it is idiomatic.
For fundamental types, you can use things like:
int i;
i = 10;
i = someFunction();
You can use them in a chain operation.
int j = i = someFunction();
You can use them in a conditional.
if ( (i = someFunction()) != 0 ) { /* Do something */ }
You can use them in a function call.
foo((i = someFunction());
They work because i = ...
evaluates to a reference to i
. It's idiomatic to keep that semantic even for user defined types. You should be able to use:
Test a;
Test b;
b = a = someFunctionThatReturnsTest();
if ( (a = omeFunctionThatReturnsTest()).getAge() > 20 ) { /* Do something */ }
More importantly, you should avoid writing a destructor, a copy constructor, and a copy assignment operator for the posted class. The compiler created implementations will be sufficient for Test
.
Upvotes: 5
Reputation: 18368
Returning reference to the original object is needed for support of nested operations. Consider
a = b = c
Upvotes: 3