Constructors:
All the objects which you will develop will hold some memory space,
size of which depends on what all are the attributes of that object.
For example if an object happens to have int and one float
the size of the object will be the sum of the size of one int and one
float. If the object happens to hold one pointer the size of
the object will be the size of int, irrespective of how huge memory
chunk is being addressed by the pointer. To properly initialize the
object(assigning proper values to all its attributes and memory from
the heap to the pointers) you need to write proper constructor. If the
constructor doesn't take any arguments its called default
constructor. An object can have more than one constructors. In the
constructor you should take care of allocating proper memory space to
all the pointers and you shouldn't leave any pointers
dangling(uninitialized). If you don't want to allocate any memory to it,
assign it the value NULL.
Now, I have given you the basic idea of what the constructor is
really about, which most of you must be aware of it. What I intend to
tell you here is something else. Suppose, you have one class(Car)
which contains objects of other classes(say engine, tyre, etc in this
case). This is called composition.
class Car{
private:
Engine eng;
Tyre t1, t2, t3 t4;
//.....
//....
//lots of other stuffs.
public:
Car();//default constructor
Car(some parameters)//constructor
};
Now, when the car is constructed, all other composed objects are
constructed using its default constructor. But what if you intend to
call its some specific constructor, say tyre with particular air
pressure and groove size. You can't call tyre's constructor inside the
constructor of Car because, those objects are already constructed,
before the construction of Car starts. Similarly, if there is some const
variable inside the class, you can't initialize it to its constant value
inside the constructor's body.
class resistor{
private:
const resistance;
//.......
//.......
public:
resistor(float res_value){
resistance=res_vale;//error, constant variable can't
//changed
}
};
The solution provided by the language is to use constructor
initializer list. This list starts with a colon(:) after the
argument list of the constructor and ends before the opening brace.
For initializing constant variables, you type the name of that variable
and inside parenthesis give its default value, e.g.
resistor::resistor(float res_value):resistance(res_value){
//do other stuffs
//...
}
Similarly, to call the composed object's constructor, you call it in
initializer list.
Car::Car(float front_air_pressure, back_air_pressure, float groove_size, engine_parameters, other parameters):/*initializer list begins*/
/*intialize tyres*/ t1(front_air_pressure, groove_size), t2(front_air_pressure, groove_size),
t3(back_air_pressure, groove_size), t4(back_air_pressure, groove_size),
/*intialize composed class engine*/ eng(engine_parmeters){
//other stuffs
//.....
//.....
//.....
}
Initializer list is also helpful when inheritance is involved. Suppose you have a base class BASE and from it an inherited class DERIVED. When ever a class is constructed, the most base class is constructed first and then towards the derived classes. Hence, when an instance of
DERIVED class is constructed, first the BASE part is constructed and
then the extra features added by DERIVED. The problem here is same as
in the above case. The BASE class is constructed using its default
constructor. The solution is same here, You call the constructor of
BASE class in the initializer list, but here you use the name of the
base class i.e.
DERIVED::DERIVED(params_for_base, params_for_derived) : BASE(params_for_derived){
//extra stuffs
//.....
}