Constructors
- has the same name as its class
- does not have a return value(not even void)
- can have an arbitrary number of parameters of any type(except the type of that class(pointers and references are allowed))
- can have default arguments
class MyName{
int a;
char b;
public:
MyName();//constructor without parameters
MyName(int a);//constructor with 1 parameter
MyName(char b, int a=1);//constructor with a default argument
MyName(Myname mn);//ERROR!!! Constructor cannot have argument of its own class
MyName(MyName* mn);//this is okay
MyName(MyName& mn);//this is okay
};
Calling constructor
- Type identifier; // if object has Type( ) constructor(constructor without parameters)
- Type identifier(argument1,argument2,…); //if object has constructor that is compatible with these values
- Type identifier{arguments…};
- Type identifier = {argument1,argument2, …}; //same as the previous one
- Type identifier = value; // if there is a compatible constructor with only one parameter
- Type* identifier = new Type(parameters);
int main(){
MyName a;//calling MyName()
MyName b();//function declaration
MyName c('a',1);//calling MyName(char int)
MyName c2('b');//calling MyName(char int) because int has a default value
MyName d=3;//calling MyName(int)
MyName e(3,4,2);//Error, no such constructor exists
MyName f(&a);//calling MyName(MyName*)
MyName g(b);//calling MyName(MyName&)
}
Constructors can also be called explicitly. A call like that will create a temporary object.
MyName mn;
mn=MyName('a',1);
Constructor definition
class C {
int a;
char b;
public:
C():a(1),b('a'){}//initializing a and b
//or
C(){a=1;b='a';}//assigning value to a and b
C(int i):a(i+2),b('e'){}
//or
C(int i):a(i+2){b='e';}//...
};
Default constructor
Delegating constructor
In the initializer list of a constructor we can call another (target) constructor of the same class. The one that calls that target constructor is called the delegating constructor. When we do this, the target constructor executes first and then the delegating one. Also when we do this, there cannot be any other member of that initializer list besides that target constructor. We also must be wary that this can lead to recursion if not done properly (the compiler will not detect it for us so it will go into an infinite loop).
class R {
public:
R(int i){}
R():R(1){} // R() is delegating, R(int) is target
R(char c): R(0.1){} //ERROR-recursion R(char) will call R(double) and the other way around
R(double d): R(’c’){}
};
Copy constructor
class CC{
public:
CC(int i) {
this.field = i;
}
CC(const CC& target){
target.field = this.field;
} // copy constructor
private:
int field;
};
CC f(CC c1) {
CC c2=c1; // call of the copy constructor for c2
return c2; // call of the copy constructor for returning a value
}
void h() {
CC cc1=1, cc2=4;
cc1=f(cc2);/*Call of the copy constructor three times! Once from cc2 ➝ function parameter
c1, once from function parameter c1 ➝ function variable c2, once from return function
value ➝ cc1*/
}
Now if some data members are pointers, the generated constructor will only copy the value those pointers have, it will not make a copy of actual objects the pointers are pointing to (so basically pointers of both objects will then point to the same thing). In most cases, that is not the effect we want That’s why we need to make our own copy constructors when pointers are involved and do a Deep Copy, where we don’t want both pointers to point to the same location but rather allocate new memory resources with the same value.
If we want our class to forbid the use of the copy constructor (or any other constructor), then we can just simply define the copy constructor in private section or write the following:
class C {
...
C(const C&) = delete;
...
};
This will delete the specified constructor.
Conversion constructor
Constructor execution flow
- Attributes of primitive types are initialized
- constructors of data members (which are of user-defined types) are called
- If an attribute (data member) has its initializer in the class body and in the constructor definition, the initializer from the constructor definition is applied !!
- when the default constructor does not exist
- when an attribute is a constant
- when an attribute is a reference
Initializing an array of class objects
Just like with arrays of primitive types, we can use initializers in the form of a list of expressions inside curly brackets. Those expressions can be even constructor calls.
MyName mn[] = { 12, MyName( 'a', 2), MyName( ) };
If initializers are excluded, then for every object of the array, the default constructor is called (the compiler signals an error if it doesn’t exist). Objects are initialized in ascending order of an index (or to be precise in ascending order of addresses). If the operator new is used, then initializers cannot be used and only the default constructor is called for each element of the list (again, the compiler will signal an error if it doesn’t exist).
Table of contents
- Operator Overloading
- Class Inheritance
- Exceptions
- Namespaces
- Templates
- Standard Library
- Additional Problems