## Recommended Posts

Alex    122
I ran into a bit of a problem with overloading the assignment operator: something didn't work the way I expected to. I wanted to use it to convert between types. For example, the following code shows structures for 2D and 3D vectors, and simple operator overloads to convert between types:
struct VECTOR2;
struct VECTOR3;

struct VECTOR2
{
float x;
float y;

VECTOR2& operator=(const VECTOR3& in);
};

struct VECTOR3
{
float x;
float y;
float z;

VECTOR3& operator=(const VECTOR2& in);
};

VECTOR2& VECTOR2::operator =(const VECTOR3 &in)
{
x = in.x;
y = in.y;
return *this;
}

VECTOR3& VECTOR3::operator =(const VECTOR2 &in)
{
x = in.x;
y = in.y;
z = 0.0f;
return *this;
}


The problem is, the following doesn't seem to work:
VECTOR2 v1;
v1.x = 5;
v1.y = 7;
VECTOR3 v2 = v1;


The code above gives the error "cannot convert from 'const Horizon::VECTOR3' to 'Horizon::VECTOR2'", but the code below works:
VECTOR2 v1;
v1.x = 5;
v1.y = 7;
VECTOR3 v2;
v2 = v1;


Anyone have an explanation of why one works and the other doesn't? Also, is there anything that can be done to make the first snippet also work? Thanks!

##### Share on other sites
SiCrane    11839
Here:
VECTOR3 v2 = v1;

The assignment operator isn't called for VECTOR3; the constructor is being called. If you want it to work you need to add a constructor that will accept a VECTOR2 as an argument.

##### Share on other sites
Mattijs2    122
The line

VECTOR3 v2 = v1 ;

is 'rewritten' by the compiler as

VECTOR3 v2 (v1) ;

which makes it more obvious that the overloaded assignment operator is not called and that you need a constructor like

VECTOR3::VECTOR3 (const VECTOR2 &in) ;

There must be a good reason why it's done like this, but I would rather like to have the operator= being called whenever you see a '='. You get similar issues when using

VECTOR3 v1 ;
VECTOR3 v2 = v1 ;

Only in this case, the compiler will automatically generate the

VECTOR3::VECTOR3 (const VECTOR3 &in) ;

constructor. This constructor will do a shallow copy of the members of the objects. In this case it's called the copy constructor, and you only have to define one yourself when a shallow copy of members is not enough. For example, when you have members that are pointers. Classic example is a string class with the string itself as a private char * member that is dynamically allocated.

##### Share on other sites
rip-off    10976
Quote:
 There must be a good reason why it's done like this

There is. Assignment and initialisation are two very different things. In the assignment operator overload, you can assume that the class already has state. In initialisation, you are setting up that state.

For POD types or similar, there usually isn't a huge difference in implementation - the main difference typically being use of initialiser lists rather than assignments in the body. For complex types there would be - you also have to tidy up the old state in the assignment operator.

Quote:
 ... In this case it's called the copy constructor, and you only have to define one yourself when a shallow copy of members is not enough...

True, but also remember the rule of three.

##### Share on other sites
Mattijs2    122
Ah, that is very true. However, if you are new to the language, it must be confusing. Wouldn't it be better to only use the copy constructor when you write something like cPerson john (bill) ; and let the compiler interpret cPerson john = bill ; as (cPerson john) = bill. So, first create an object john of type cPerson, and then do the assignment operation. In that case the source code more accurately describes what is going on.

The copy constructor is also used when an object is passed by value, which you can see as an assignment operation. But there is no '=' in the code, so I don't think this will confuse people.