Welcome to our deep dive into C++ Virtual Destructor! In this comprehensive lesson, we'll explore the concept from the ground up, making it accessible for both beginners and intermediates.
A virtual destructor in C++ is a destructor that is declared within a base class and is overridden in a derived class. It ensures that the correct destructor is called when an object of a derived class is destroyed, even if the object's type is upcasted to its base class.
When an object is deleted, its destructor is called to clean up any resources allocated by the object. If a base class pointer points to a derived class object and the destructor is not virtual, the base class destructor will be called, possibly leaving the resources allocated by the derived class un-deallocated. To prevent this, we use a virtual destructor.
A virtual destructor is defined using the virtual keyword in the base class. Here's an example:
// Base class
class Base {
public:
virtual ~Base() {
std::cout << "Base class destructor called.\n";
}
};
// Derived class
class Derived : public Base {
public:
Derived() {
std::cout << "Derived class object created.\n";
}
~Derived() {
std::cout << "Derived class destructor called.\n";
}
};
int main() {
Derived d; // Derived class object created
Base* b = &d; // Upcasting the derived object to a base pointer
delete b; // Deleting the base pointer
return 0;
}In the above example, when the line delete b; is executed, the destructor of the base class (Base) is called first. However, since Base is a virtual destructor, the destructor of the derived class (Derived) is also called, ensuring that all resources allocated by the derived class are properly deallocated.
What is the purpose of a virtual destructor in C++?
Consider a simple example of a Shape base class and a Circle derived class. The Circle class allocates memory for a double to store the radius. When a Circle object is deleted, its destructor is responsible for deallocating the memory. If a Shape pointer points to a Circle object and the destructor is not virtual, the memory allocated by the Circle will not be deallocated, leading to a memory leak.
// Base class
class Shape {
public:
virtual ~Shape() {
std::cout << "Base class destructor called.\n";
}
};
// Derived class
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {
std::cout << "Circle object created with radius: " << radius << "\n";
}
~Circle() {
std::cout << "Circle destructor called. Deallocating memory.\n";
// Deallocate memory for radius
}
};
int main() {
Circle c(5); // Create a Circle object
Shape* s = &c; // Upcast the Circle object to a Shape pointer
delete s; // Delete the Shape pointer
return 0;
}In this example, the Circle class allocates memory for its radius, and the destructor is responsible for deallocating it. Without a virtual destructor, the memory would not be deallocated when the Shape pointer is deleted.
In this lesson, we've explored the concept of a virtual destructor in C++, its importance, and how to define and use it. We've also seen a real-world example to illustrate its practical application. Now that you've learned about virtual destructors, you're one step closer to becoming a proficient C++ programmer!
Remember to practice and experiment with these concepts to solidify your understanding. Happy coding! š»š§š