Constructors
Explore how constructors work in C++ classes, including their types such as default, parameterized, and copy constructors. Understand how to initialize objects properly, use initializer lists, and the importance of deep copying versus shallow copying in class design.
Introduction
Constructors are special member functions of a class that are automatically called when an object of the class is created.
A constructor is a member function that is usually
public.A constructor can be used to initialize member variables when an object is created.
A constructor’s name must be the same as the name of the class it is declared in. A constructor cannot return a value. So, no return type, not even void can be used while declaring a constructor. If no constructor is declared, C++ will generate a default constructor that initializes data members to default values.
Declaration and initialization
Constructors are mostly public. We can declare and initialize the constructor within the class or declare it inside the class and write the method outside the class.
A constructor for the DayofYear class can be declared as follows:
Unlike normal member functions of a class, a constructor can’t be called by using . operator or -> operator. Constructors are automatically called when we create an object of a class.
Types of constructors
There are three different types of constructors:
Default constructor
Parameterized constructor
Copy constructor
Default constructor
A default constructor either takes no parameters or has default arguments for all parameters. It initializes the object with default values. It’s like a default initialization process for the object. Here’s an example default constructor:
Here, we assign default values 1 to the data members, i.e., month and day of DayOfYear class.
Note: It’s a good practice to use default constructors even if you don’t want to initialize any variables.
Parameterized constructor
A parameterized constructor takes one or more arguments and allows us to initialize objects with specific values.
In the above code, the constructor for the DayOfYear class takes two parameters new_month and new_day and then we use these parameters to set the values of data members of the class. Just like functions, a constructor can also have default parameter values. This allows us to call the constructor with fewer arguments than the number of parameters defined. If we do not provide a value for a parameter, the default value is used.
Initializer lists
Sometimes, instead of assigning values inside the constructor body, we initialize data members directly after the constructor parameters. This is called an initializer list.
An initializer list begins with a colon : after the constructor declaration, followed by the data members and the values used to initialize them.
class DayOfYear {public:DayOfYear(int new_month, int new_day): month(new_month), day(new_day){}private:int month;int day;};
In this example, month and day are initialized directly using the values passed to the constructor.
This approach is often cleaner than assigning values inside the constructor body, especially as classes become larger.
Note: Initializer lists are required when initializing
constdata members, reference members, or member objects that do not have a default constructor.
Copy constructor
A copy constructor initializes an object as a copy of another existing object of the same class. It takes a reference to an object of the same class as an argument. It is used when an object is passed by value, returned from a function, or explicitly copied.
For example, we can have a copy constructor like this:
In the above code, the & in the copy constructor indicates that the object is month and day values of the new object by directly copying them from the existing object (obj). Here’s how the copy constructor is called:
In this code, anotherDay is created as a copy of birthday. This is an example of shallow copy. It simply copies the values of month and day from birthday to anotherDay.
However, shallow copy can be problematic if the class uses dynamic memory (e.g., pointers). Both objects would then share the same memory, which can cause issues like double deletion.
To solve this, we use a deep copy, where each object gets its own memory for any dynamically allocated data. Here’s an example of how you can implement a deep copy:
Now, with deep copy, when anotherDay is created, it gets its own separate memory for month and day. This prevents the issues that can arise with shallow copy, such as shared memory between objects. This avoids the risks associated with shallow copy, like double deletion or memory corruption.
Example
Let’s look at DayOfYear class we defined in a previous lesson:
Line 22: The parameterized constructor is called. Here are some key points to note regarding the constructor:
It is called in object declaration.
It creates a
DayOfYearobject.Then calls the constructor to initialize variables.
Line 23: The default constructor is automatically called when we create an object. This constructor takes no parameters and just initializes
monthanddayto 0.
Constructor overloading
Just like functions, constructors can be overloaded by defining constructors with different parameter lists. For example, other possible constructors for DayOfYear class can be the following:
Destructor
Like a constructor, a destructor is a special member function that is automatically called when an object goes out of scope or is explicitly deleted. We use the destructors to clean up resources that the object may have acquired, such as memory. Unlike constructors, destructors cannot take arguments or return values, and each class can have only one destructor.
Syntax
Like constructors, a destructor is defined with the same name as the class, preceded by a tilde (~). It does not have any parameters or a return type.
Quiz
To test your comprehension of the concepts discussed in this lesson, answer the questions given below:
What is the purpose of a constructor in C++?
To allocate memory for an object
To define the data members of a class
To initialize the object when it is created
To destroy an object when it goes out of scope