Copy Constructor & assignment operator=

Used to make a copy of an existing object.

 

 

Copy Constructor

Takes one parameter, which is a reference (i.e. using an & to create an alias) to the object being copied, of the same class data type.

 

The usual signature of a copy constructor is as follows:

 

ClassName::ClassName(const ClassName & source) :

 

 

If a copy constructor is not defined, the compiler provides an implicit copy constructor that provides a member level copy of the source object.

 

This type of member wise copy is also known as shallow copy.

 

For example, given a simple class definition with 3 attributes:

 

class MyClass {

int myInt ;

float myFloat ;

string myString ;

} ;

 

The compiler would provide an implicit copy constructor that is equivalent to:

 

MyClass::MyClass( const MyClass & source) :

myInt( source.myInt ),

myFloat( source.myFloat ),

myString( source.myString )

{ }

 

An initialiser list has been used to define each of the 3 attributes in this example, but of course the compiler implicit copy constructor would copy N attributes as required for the number of object attributes.

 

The use of the keyword const in the copy constructor signature ensures that the passed in reference (alias) to the object will not be changed, thus ensuring the original remains intact and that the copy constructor acts upon the new object without being able to change the original.

 

 

Assignment operator=

Another form of copying is provided by the = assignment operator, whereby a copy of an existing object is assigned to another. In this case, both objects must exist in the first place for the assignment operator to come into effect, otherwise a copy constructor would be invoked as per the above.

 

The usual signature of assignment = operator is as follows:

 

ClassName & operator=(const ClassName & source)

 

 

The assignment operator= is also implicitly provided by the compiler if it has not been defined, and taking the example class above would be equivalent to:

 

MyClass & operator=( const MyClass & source) {

myInt = source.myInt ;

myFloat = source.myFloat ;

myString = source.myString ;

return *this ;

}

 

Here, the assignment operator = is being overloaded and redefined within the body of its code block. The keyword operator followed by the operator to be overloaded (e.g. =) are defined after the return type of the object, which is of course the class name (in this example myClass). The reference to the object being copied is then used as the source, where in the body it assigns the attributes to the new object (in this example just the 3 primitives) and returns the new object itself via the *this self pointer.

 

It must be noted that the copy constructor and the assignment operator, are two of the "Rule of Three" with third being the destructor, whereby if the default (implicit) versions of any of these three needs to be defined, then it is likely that all three need to be defined.

 

As we have seen above, the copy constructor and the assignment operator have different implementations, and are therefore invoked in different ways.

 

The copy constructor is invoked when the object being copied is used as the parameter for a new object definition.

 

e.g. assuming MyClass objectA ; //create a new object called objectA

then MyClassB objectB(objectA) ; //uses objectA as the parameter to be copied to create objectB

 

 

Alternatively, the assignment operator= is invoked when the two objects already exist.

 

e.g. MyClass objectC ; //create a new object called objectC

then assigning an existing object to the new object e.g. MyClass objectC = objectA ;

 

What's actually happening here is that the assignment operator = is being overloaded and objectA is being used as its parameter.

 

This example shows an objectA being instantiated, which is then used in the copy constructor to instantiate objectB. Next, objectC is instantiated with its own attributes and some text is displayed before the operator= assignment is called, then at the start of the operator= assignment and again at the end of the operator assignment. At this point, the newly copied object is returned using the *this self pointer, which actually returns a reference to the object as indicated by the use of the ampersand & being indicated as the return type at the beginning of the signature.

 

To emphasize, an assignment operator returns a reference to the target object. This allows chaining of assignments, e.g. objectC = objectB = objectA ;

 

Compile & Run:

objectA is instantiated and contains: 17, 3.1416, Apollo

objectB is instantiated via the COPY CONSTRUCTOR and also contains: 17, 3.1416, Apollo

objectC is instantiated and contains: 12, 9.666, Hammer time!
ASSIGNMENT 'OPERATOR=' CALLED
objectC now contains: 17, 3.1416, Apollo

objectD is instantiated, but since it did not exist before it uses the COPY CONSTRUCTOR
and we can see it also contains: 17, 3.1416, Apollo

Leave a Reply