Classes & Objects
Constructors & Destructors
Initialise objects automatically: default, parameterised and copy constructors, initialiser lists, constructor overloading, and destructors with the order they run in.
A constructor is a special member function that runs automatically when an object is created. Its job is to put the object into a valid starting state.
- Same name as the class.
- No return type — not even
void. - Can be overloaded.
Default and parameterised constructors
#include <iostream>
#include <string>
using namespace std;
class Student {
string name;
int roll;
public:
Student() { // default constructor: no arguments
name = "Unknown";
roll = 0;
cout << "default constructor" << endl;
}
Student(string n, int r) { // parameterised constructor
name = n;
roll = r;
cout << "parameterised constructor for " << n << endl;
}
void show() { cout << roll << ": " << name << endl; }
};
int main() {
Student a; // calls Student()
Student b("Meera", 12); // calls Student(string, int)
Student c = {"Kiran", 13}; // also the parameterised one
a.show(); b.show(); c.show();
return 0;
}default constructor parameterised constructor for Meera parameterised constructor for Kiran 0: Unknown 12: Meera 13: Kiran
Initialiser lists
The preferred way to initialise members is a member initialiser list, after a colon. It initialises members directly instead of assigning them afterwards, and it is required for const members, reference members and base classes.
#include <iostream>
using namespace std;
class Circle {
const double PI; // const members must use the initialiser list
double radius;
public:
Circle(double r = 1.0) : PI(3.14159), radius(r) {} // also a default constructor
double area() const { return PI * radius * radius; }
};
int main() {
Circle unit, big(10);
cout << unit.area() << " " << big.area() << endl;
return 0;
}3.14159 314.159
Copy constructor
The copy constructor creates a new object as a copy of an existing one. It takes a const reference to an object of the same class. It runs when you:
- initialise one object from another:
Point b = a;orPoint b(a); - pass an object by value to a function;
- return an object by value (often optimised away).
#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
Point(const Point &other) : x(other.x), y(other.y) { // copy constructor
cout << "copying (" << x << ", " << y << ")" << endl;
}
void show() const { cout << "(" << x << ", " << y << ")" << endl; }
};
void display(Point p) { p.show(); } // by value: copies
int main() {
Point a(3, 4);
Point b = a; // copy constructor
display(a); // copy constructor again
b.show();
return 0;
}copying (3, 4) copying (3, 4) (3, 4) (3, 4)
Destructors
A destructor runs automatically when an object is destroyed — when it goes out of scope, or when you delete it. Its name is the class name with a tilde: ~Student(). It takes no arguments, returns nothing, and cannot be overloaded. Use it to release resources: memory, files, network connections.
#include <iostream>
#include <string>
using namespace std;
class Tracer {
string name;
public:
Tracer(string n) : name(n) { cout << " construct " << name << endl; }
~Tracer() { cout << " destroy " << name << endl; }
};
Tracer global("global");
int main() {
cout << "main starts" << endl;
Tracer a("a");
{
Tracer b("b");
Tracer c("c");
cout << " leaving inner block" << endl;
} // c then b destroyed here
Tracer *d = new Tracer("d (heap)");
delete d; // destroyed only when deleted
cout << "main ends" << endl;
return 0;
} // a destroyed, then globalconstruct global main starts construct a construct b construct c leaving inner block destroy c destroy b construct d (heap) destroy d (heap) main ends destroy a destroy global
Objects are destroyed in the reverse order of construction — like a stack.
Managing a resource: a dynamic array class
#include <iostream>
using namespace std;
class IntArray {
int *data;
int size;
public:
IntArray(int n) : data(new int[n]()), size(n) {} // () zero-initialises
IntArray(const IntArray &o) : data(new int[o.size]), size(o.size) { // deep copy
for (int i = 0; i < size; i++) data[i] = o.data[i];
}
~IntArray() { delete[] data; }
int &at(int i) { return data[i]; }
int length() const { return size; }
};
int main() {
IntArray a(5);
for (int i = 0; i < a.length(); i++) a.at(i) = i * i;
IntArray b = a; // deep copy: b gets its own memory
b.at(0) = 100;
cout << "a[0] = " << a.at(0) << ", b[0] = " << b.at(0) << endl;
return 0;
}a[0] = 0, b[0] = 100
Without the copy constructor, b would share a's pointer (a shallow copy): changing b would change a, and both destructors would delete[] the same memory. More on this in Dynamic Memory & Smart Pointers.
Test yourself
4 questions · pick an answer to check it instantly
- 1
Which is true of constructors?
Constructors run automatically, have no return type and can be overloaded. - 2
When is the copy constructor not called?
Assigning to an existing object uses the copy assignment operator, not the copy constructor. - 3
In what order are local objects
x,y,z(created in that order) destroyed?Destruction happens in reverse order of construction. - 4
Which members must be initialised in the initialiser list?
Const and reference members cannot be assigned after construction, only initialised.