A misunderstanding with polymorphism and virtual destructors - c++

Example:
class Base {
public:
virtual void f() = 0;
virtual ~Base() { std::cout << "Base::~Base()\n"; }
};
class Derived : public Base {
public:
void f() { }
~Derived() { std::cout << "Derived::~Derived()\n"; }
};
int main() {
Base* p = new Derived();
delete p;
return 0;
}
Output:
Derived::~Derived()
Base::~Base()
I thought only the derived class destructor will be called since the pointed object to be freed is an instance of the derived class.
I have two questions:
Why was the virtual base destructor called?
Is it legally possible (or should it even be possible) to prevent the base class destructor from being called?

Why was the virtual base destructor called?
Because base class should be properly destructed. Derived class can not possibly do this.
Is it legally possible (or should it even be possible) to prevent the
base class destructor from being called?
No, because it would prevent properly destructing the base class (i.e. call it's members destructors)

Related

What does the operator '~' do when it is beside a method and what is a pure virtual method for?

Example code:
#include <string>
namespace vehicle
{
class Vehicle
{
public:
Vehicle(int a);
virtual ~Vehicle(); <------ not method?
protected:
int a;
};
}
Also, I don't fully get the concept of a pure virtual method where you declare a method as:
virtual method() = 0;
Why do we need this?
Let's suppose there are two classes: Base and Derived
struct Base
{
Base() {}
virtual void foo() = 0;
virtual ~Base()
{
std::cout << "Base descructor" << std::endl;
}
};
struct Derived : Base
{
int *i;
Derived(int i_): Base(), i(new int[i_]) {}
virtual void foo() override
{
std::cout << "foo" << std::endl;
}
virtual ~Derived()
{
std::cout << "Derived descructor" << std::endl;
delete [] i;
}
};
Pure virtual functions
If Derived doesn't override the foo function you can create an instance of the Derived class. When you try, your code will not compile, because foo is a pure virtual function.
error: invalid new-expression of abstract class type 'Derived'
note: because the following virtual functions are pure within 'Derived':
struct Derived : Base
Pure virtual functions are used to describe the interface.
Now about virtual destructors:
The ~(tilda) sign is used to denote the class destructor. It
is a special method that is called when the object is destroyed.
A client creates an instance of Derived:
Base *instance = new Derived;
then this variable is used somehow and when you don't need the variable you need to free the memory:
delete instance;
Let's trace the calls:
Derived descructor
Base descructor
So you can see that both base and derived destructors are called and no memory leak is possible. But if you remove this virtual keyword from the destructors
Base descructor
As you can see the descturtor of Derived is not called, so a memory leak exists (the array of Derived class don't get released).
Hence virtual constructors are useful when you work with objects through pointers.
virtual ~Vehicle();
The tilde ~ denotes a destructor. It's a method, a special method for destroy the object.
Virtual destructor is used in abstract base class.
virtual method() = 0;
That's pure virtual function. It indicates that you have to provide implementation method for the implementation class implementing this abstract base class.

Protected non-virtual destructor in the base class

I am trying to understand virtual destructors. The following is a copy paste from this page When to use virtual destructors?
Here, you'll notice that I didn't declare Base's destructor to be
virtual. Now, let's have a look at the following snippet:
Base *b = new Derived(); // use b
delete b; // Here's the problem!
[...] If you want to prevent the deletion of an instance through a base class pointer, you can make the base class destructor protected and non-virtual; by doing so, the compiler won't let you call delete on a base class pointer.
I don't understand why the deletion is prevented by having a protected non-virtual base class destructor. Doesn't the compiler think that we're trying to call delete from a base class object? What does protected have to do with that?
The C++ Standard has this to say about delete (section 5.3.5p10):
Access and ambiguity control are done for both the deallocation function and the destructor (12.4, 12.5).
Therefore, only code that has access to the destructor is able to use delete. Since the destructor is protected, that means that no one can call delete on a pointer of type Base*. Only subclasses can use the destructor at all (and the only thing that will is the subclass's own destructor, as part of the subobject destruction process).
Of course, the subclass should make its own destructor public, allowing you to delete objects through the subclass type (assuming that is the correct actual type).
NOTE: Actually, other members of Base can do delete (Base*)p; since they have access. But C++ assumes that someone using this construct will not be doing that -- C++ access control only provides guidance to code outside your class.
delete b; effectively performs b->~Base(); deallocate(b);. The first part - calling the destructor - would fail to compile if the destructor is inaccessible (in the same way that calling any other inaccessible method fails).
From my understanding (based on this page), the only case we would like to use the non-virtual and protected destructor in the base class is the following:
#include <iostream>
struct unary_function {
protected:
~unary_function() {
std::cout << "unary_function" << std::endl;
}
};
struct IsOdd : public unary_function {
public:
bool operator()(int number) {
return (number % 2 != 0);
}
};
void f(unary_function *f) {
// compile error
// delete f;
}
int main() {
// unary_function *a = new IsOdd;
// delete a;
IsOdd *a = new IsOdd;
delete a;
getchar();
return 0;
}
therefore, you can only do this:
IsOdd *a = new IsOdd;
delete a;
or
IsOdd c;
never these:
unary_function *a = new IsOdd;
delete a;
therefore, with nonvirtual protected destructor, the compiler would give an error when you try to use this
void f(unary_function *f) {
delete f;
// this function couldn't get compiled because of this delete.
// you would have to use the derived class as the parameter
}
Protected methods and variables of a class (let's call it Base) can only be accessed by derived classes. Thus, if you call delete on a pointer of type Base outside a derived class, it will try to call Base::~Base() (Base's destructor), but since it is protected, it cannot be called, which thus results in a compilation error.
According to the specification, the destructor of a base class must only be declared protected and non-virtual (to not allow deletion of a derived object through a Base pointer), or public and virtual (to allow safe deletion of a derived object through a Base pointer).
If a destructor is declared public and non-virtual, it results in undefined behaviour if a pointer of type Base which points to a derived class is deleted.
The two options:
Non-virtual protected destructor - Base pointer to Derived cannot be deleted:
class Base {
public:
Base() {
std::cout << "Base ctor called.\n";
}
protected:
~Base() {
std::cout << "Base dtor called.\n";
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived ctor called.\n";
}
~Derived() {
std::cout << "Derived dtor called.\n";
}
};
Base *foo = new Derived;
delete foo; // compilation error
... as mentioned in your question.
Public virtual destructor - allows a pointer of type Base to a Derived object to be deleted. First the Derived destructor is called, and then the Base destructor is called:
class Base {
public:
Base() {
std::cout << "Base ctor called.\n";
}
virtual ~Base() {
std::cout << "Base dtor called.\n";
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived ctor called.\n";
}
~Derived() override {
std::cout << "Derived dtor called.\n";
}
};
Base *foo = new Derived;
delete foo;
Output:
Base ctor called.
Derived ctor called.
Derived dtor called.
Base dtor called.

Why is base-class destructor called on derived object when destructor of derived class is non-virtual?

Why are all destructors, ~D(),~C(),~B(),~A() being called in the example below?
There is only one virtual destructor: that of A.
Here is the code:
#include<iostream>
using namespace std;
class A
{
public:
virtual ~A()
{
cout<<"destruct A\n";
}
};
class B:public A
{
public:
~B()
{
cout<<"destruct B\n";
}
};
class C:public B
{
public:
~C()
{
cout<<"destruct C\n";
}
};
class D:public C
{
public:
~D()
{
cout<<"destruct D\n";
}
};
int main()
{
A* ptr = new D();
delete ptr;
return 0;
}
Once A's destructor is declared virtual, the destructors of all derived classes are also virtual, even if they aren't explicitly declared as such.. So the behaviour you see is exactly what is expected
The destruction order in derived objects goes in exactly the reverse
order of construction: first the destructors of the most derived
classes are called and then the destructor of the base classes.
A destructor can be defined as virtual or even pure virtual. You would
use a virtual destructor if you ever expect a derived class to be
destroyed through a pointer to the base class. This will ensure that
the destructor of the most derived classes will get called:
A* b1 = new B;//if A has a virtual destructor
delete b1;//invokes B's destructor and then A's
A* b1 = new B;//if A has no virtual destructor
delete b1;//invokes A's destructor ONLY
If A does not have a virtual destructor, deleting b1 through a pointer
of type A will merely invoke A's destructor. To enforce the calling of
B's destructor in this case we must have specified A's destructor as
virtual:
virtual ~A();
REFERENCE
As #juanchopanza said - declaring the base destructor virtual means all descendants have virtual destructors. This inherited virtuality is the same for any methods, not just destructors.
It's why I have interviewed people who didn't know what the keyword did because they had only ever had to override methods derived from a framework, so they were all virtual (sigh).

class has virtual functions and accessible non-virtual destructor

I have two classes:
class A {
public:
virtual void somefunction() = 0;
};
class B : public A {
public:
B();
~B();
void somefunction();
};
B::B() {}
void B::somefunction() {
// some code
}
But with g++ I get errors:
class A has virtual functions and accessible non-virtual destructor
class B has virtual functions and accessible non-virtual destructor
I don't have any idea what this error is... Somewhere on blogs I read that it's a compiler warning. How can I fix the problem?
This happens because your base class A does not have a virtual destructor. For instance, if you had this code:
int main()
{
A* a = new B;
delete a;
}
Then the delete a call would not be able to call B's destructor because A's isn't virtual. (It would leak all of B's resources.) You can read more about virtual destructors here.
Add a virtual destructor to your base class and you should be fine.
class A
{
public:
virtual void somefunction() = 0;
virtual ~A() = default;
}
Give class A:
virtual ~A() { }
That way, derived classes such as B will still have their custom destructor called if you delete them via an A*.
As thumb rule(IMHO) or in Short the destructor in the base class has to be either public and virtual or protected non virtual to prevent the memory leaks.by doing so the destructors of the derived class get called and this prevents the memory leakage whenever the Base pointer/reference holding derived address/reference is deleted.
If a class has virtual functions then its destructor should be virtual as well. Yours has an accessible destructor but it is not virtual.

Scope of pure virtual functions during derived class destruction - In C++

During destruction of the derived class object, i first hit the derived class destructor and then the base class destructor (which is as expected). But i was curious to find out - at what point does the functions of the derived class go out of scope (are destroyed).
Does it happen as soon as the control leaves the derived class destructor and goes toward the base? Or does it happen once we done with the base class destructor also.
Thanks
Once the destructor of the most derived class finishes, the dynamic type of the object can be considered that of the next less-derived-type. That is, a call to a virtual method in the base destructor will find that the final overrider at that point in time is at base level. (The opposite occurs during construction)
struct base {
base() { std::cout << type() << std::endl; }
virtual ~base() { std::cout << type() << std::endl; }
virtual std::string type() const {
return "base";
}
};
struct derived : base {
virtual std::string type() const {
return "derived";
}
};
int main() {
base *p = new derived;
std::cout << p->type() << std::endl;
delete p;
}
// output:
// base
// derived
// base
Functions don't get destroyed.
Virtual functions however get their entry in the v-table erased as soon as the derived destructor finishes so you can't call derived virtual functions from the base d'tor.