Wednesday 2 June 2010

Class initialisation and constructors

There is often lots of confusion with regards to class initialisation. People may forget to take care while using default constructors and copy constructors. Here is a simple example that tries to explain lots of concepts.





//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This program gives an example of constructors and initialisations

#include<iostream>

using namespace
std;

//Example of a class
class someClass1
{

public
:
//implicit default constructor
int x;
int
*y;
};


//Example of a class with constructor
class someClass2
{

public
:
someClass2(const someClass2& xyz)
{

cout<<"** copy constructor called"<<endl;
x = xyz.x;
y = new int(*xyz.y);
}

//default constructor will have to be explicitly defined
someClass2() {};
//overloading operator '='
const someClass2& operator = (const someClass2& xyz)
{

cout<<"** operator '=' called"<<endl;
x = xyz.x;
y = new int(*xyz.y);
return
*this;
}

int
x;
int
*y;
};


int
main()
{

someClass1 a; //Default initialisation
a.x = 1234;
a.y = new int(6789);

cout<<"someClass1: a.x = "<<a.x<<" a.y( " <<a.y<< " ) = "<<*(a.y)<<endl;

someClass1 b = a; //Copy Initialisation

cout<<"someClass1: b.x = "<<b.x<<" b.y( " <<b.y<< " ) = "<<*(b.y)<<endl;

someClass1 c(a); //Direct Initialisation

cout<<"someClass1: c.x = "<<c.x<<" c.y( " <<c.y<< " ) = "<<*(c.y)<<endl;

//Calling default constructor
someClass2 aa;
aa.x = 2468;
aa.y = new int(3579);

cout<<"someClass2: aa.x = "<<aa.x<<" aa.y( " <<aa.y<< " ) = "<<*(aa.y)<<endl;

//calling copy constructor
someClass2 bb = aa; //Copy Initialisation - note copy constructor will be called

cout<<"someClass2: bb.x = "<<bb.x<<" bb.y( " <<bb.y<< " ) = "<<*(bb.y)<<endl;

//calling copy constructor
someClass2 cc(aa); //Direct Initialisation - note copy constructor called in this case as well

cout<<"someClass2: cc.x = "<<cc.x<<" cc.y( " <<cc.y<< " ) = "<<*(cc.y)<<endl;

someClass2 dd;
//calling operator =
dd = aa;

cout<<"someClass2: dd.x = "<<dd.x<<" dd.y( " <<dd.y<< " ) = "<<*(dd.y)<<endl;

return
0;
}







The output is as follows:

There are certain things worth noting in the above example:
  • In case of someClass1, since only the default constructor is used, the same pointer is used for y in all the cases. This can cause serious problems in the code if one of the classes delete the memory pointed by y for class someClass1. This problem is not present in someClass2
  • If any constructor is defined, it becomes necessary to define the default constructor. You can make sure that nobody uses default constructor in case of someClass2 by making it private (I havent done that because I wanted to show operator =)
  • As you can see in case of variable cc, copy constructor would always be called instead of operator =.
  • operator = would only be called in case of assignment. This is a common mistake.
  • In the code above, cc(aa) is better than using bb = aa even though the results are the same. The main advantage being that it will avoid confusion with operator '=' if its overloaded for a novice and the constructor can be overloaded to take more than one input in future.

No comments:

Post a Comment