Examples of Destructor in C++
Destructor is a basic function called automatically when the class object is deleted or goes out of the scope. We can also call the destructor manually.
The main aim of a destructor is to deallocate the memory and resources held by the object, which helps in reusing the memory and resources. This process is crucial to prevent memory leaks and ensure cleanup operations are executed properly.
Syntax:
~ class_name()
The syntax for destructor is very simple as it is just the class name preceded by the tilde symbol.
Example
Let us see the example program to understand better about the syntax.
#include <iostream>
int main() {
class Student{
public:
//constructor
Student(){
std::cout<<"Constructor called"<<"\n";
}
// destructor
~Student()
{
std::cout<<"Destructor called"<<"\n";
}
};
Student s1;
return 0;
}
Output:
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp1.png)
Explanation:
When a Student object exits the scope or is manually deleted, the destructor is immediately invoked, allowing you to do any necessary cleanup activities. Cleanup activities involve freeing dynamically allocated memory and closing open files or other resources.
More about destructor
- The destructor does not take any parameters and returns nothing.
- You cannot declare a destructor as volatile, const, or static, but you can use the destructor to destroy objects declared as such.
- The destructors share the same name as the class but with a tilde (~).
- If a destructor is not defined for a class, the compiler will automatically generate a default one.
- Destructors cannot be overloaded.
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp2.png)
Destructors are called when?
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp3.png)
Destructors in inheritance
The derived class destructor gets invoked first, then the base class.
Example 1:
#include <iostream>
class Father {
public:
//constructor
Father() {
}
//destructor
~Father() {
std::cout << "Destructor of Father class invoked" << "\n";
}
};
class Children : public Father {
public:
//constructor
Children() {
}
//destructor
~Children() {
std::cout << "Destructor of Children invoked" << "\n";
}
};
int main() {
Children c1;
return 0;
}
Output:
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp4.png)
Explanation:
This program showcases how destructors get executed in inheritance. Destructors always follow the opposite order of constructors. In the inheritance hierarchy, the destructors get called first in the derived class and then in the base class.
Example 2:
#include <iostream>
class Animal{
public:
Animal() {
std::cout<<"Constructor of Animal class invoked"<<"\n \n";
}
~Animal() {
std::cout << "Destructor of Animal class invoked" << "\n \n";
}
};
class Dog : public Animal {
public:
Dog() {
std::cout<<"Constructor of Dog class invoked" << "\n \n";
}
~Dog() {
std::cout << "Destructor of Dog class invoked" << "\n \n";
}
};
int main() {
Dog d1,d2;
return 0;
}
Output:
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp5.png)
Explanation:
When defining a class that contains multiple objects, the constructors are executed in a specific order. First, the base class constructor is executed, followed by the derived class constructor. On the other hand, when it comes to destructors, the derived class destructor is executed before the base class destructor.
To avoid incomplete cleanup, we use virtual destructors.
Without virtual destructor
Program
#include<iostream>
class King{
public:
King() { }
~King() { std::cout << "King destructor" << std::endl; }
};
class Prince: public King {
public:
Prince() { }
~Prince() { std::cout << "prince destructor" << std::endl; }
};
int main() {
King* ptr = new Prince();
delete ptr; // Problem! Only the Base destructor is called
return 0;
}
Output:
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp6.png)
Explanation:
Only the base class destructor is called when deleting the ptr in this scenario, resulting in incomplete cleanup and the possibility of resource leaks since the derived class destructor is not invoked.
With virtual destructor
Program
#include<iostream>
class King{
public:
King() { }
virtual ~ King() { std::cout << "King destructor" << std::endl; }
};
class Prince: public King {
public:
Prince() { }
~Prince() { std::cout << "prince destructor" << std::endl; }
};
int main() {
King* ptr = new Prince();
delete ptr; // Problem! Only the Base destructor is called
return 0;
}
Output:
![Examples of Destructor in C++](https://static.tutorialandexample.com/cpp/examples-of-destructor-in-cpp7.png)
Explanation
When the base class destructor is made virtual, it ensures that both the base and derived class destructors are called when an object of the derived class is deleted through a base class pointer. Virtual destructor guarantees complete cleanup.
Conclusion:
In C++ programming, destructors play a crucial role in managing resources and terminating the lifecycle of objects. They are responsible for freeing up resources such as memory, file handles, and other acquired assets when an object ends its lifecycle. Destructors are invoked when objects are deleted or go out of scope and prevent memory leaks while ensuring a smooth exit. By implementing well-structured destructor logic, programmers can rely on them to maintain the integrity of their applications. Destructors are crucial in ensuring efficient memory use and maintaining order in object creation and dissolution. They achieve this through memory deallocation and custom cleanup routines.
If a class is intended to serve as a base for other classes, it is recommended to define its destructor as virtual. It guarantees that when a derived class object is deleted through a pointer to the base class, the destructors of both the base and derived classes are called in the proper order.