use of virtual keyword in destructors

please have a look at the following code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Base
{
public:
    virtual ~Base()
    {
        cout << "Calling ~Base()" << endl;
    }
};
 
class Derived: public Base
{
private:
    int* m_pnArray;
 
public:
    Derived(int nLength)
    {
        m_pnArray = new int[nLength];
    }
 
    virtual ~Derived()
    {
        cout << "Calling ~Derived()" << endl;
        delete[] m_pnArray;
    }
};
 
int main()
{
    Derived *pDerived = new Derived(5);
    Base *pBase = pDerived;
    delete pBase;
 
    return 0;
}

Now this program produces the following result:

Calling ~Derived()
Calling ~Base()

i was reading online and got stuck here.
i am unable to understand why 'calling ~Base()' is been printed here?
when we reached delete pbase; in int main() it goes to Base class first and finds that its destructor is virtual so it goes to Derive class and finds another destructor and executes it but why does it prints ~Base() in any case?
The derived class automatically calls the base class's destructor.

Also see this:
http://www.parashift.com/c++-faq-lite/calling-base-dtor.html
sorry but i still don't find it convincing....:(
If you're not convinced by the FAQ, there's always the C++ standard document, which says, in $12.4[class.dtor]/8

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes [...] A return statement in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called.
i am unable to understand why 'calling ~Base()' is been printed here?


Short answer: "That's just how the language works"


Long answer:

Encapsulation is the idea that every class manages and takes care of itself. In order to facilitate this, every object needs to be constructed and destructed. If a destructor or constructor is not called for a class, you risk very bad side-effects (memory leaks or memory corruption, or other equally terrible bugs).


C++ implements this as illustrated below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Parent
{
public:
    Parent() { cout << "Parent ctor\n"; }
    ~Parent() { cout << "Parent dtor\n"; }
};

class Child : public Parent
{
public:
    Child() { cout << "Child ctor\n"; }
    ~Child() { cout << "Child dtor\n"; }
}

int main()
{
    {
        Child c;
    }
}
Parent ctor
Child ctor
Child dtor
Parent dtor


This guarantees the coder that the 'Parent' part of the object will be initialized and 'alive' throughout the entire life of the Child object.... since the Child portion is initialized second and destroyed first.


If you take those same classes (with no virtual dtor) and do this, you have problems:

1
2
3
4
5
int main()
{
    Parent* p = new Child;
    delete p;
}
Parent ctor
Child ctor
Parent dtor


(not I'm not sure this exact behavior is defined by the standard, but this is what will happen on most if not all implementations).

See the problem here? Child is constructed but is never destructed. This destroys encapsulation and allows for nastiness as described above (memory and other resource leaks, deadlocks, etc, etc)

This happens because the compiler only sees us deleting a Parent*. It does not know that the pointer actually points to a Child and therefore it will not call the Child dtor.

Making the destructor virtual puts the destructor in the class's vtable... which means it can figure out the type (and call the appropriate dtor) at runtime.
Topic archived. No new replies allowed.