1

When I am trying to delete the derived object polymorphically (that is: base class has public virtual destructor) why derived class private destructor is still being called? Why the scope resolution private is not working here.

class Base
{
protected:
    Base() { cout << "Base constructor.\n"; }
public:
    virtual ~Base() { cout << "Base destructor.\n"; }
};

class Derived :public Base
{
public:
    Derived() { cout << "Derived constructor.\n"; }
private:
   ~Derived() { cout << "Derived destructor.\n"; }
};

int main()
{
    Base *p = new Derived();
    delete p;
}

Output:

Base constructor.
Derived constructor.
Derived destructor.
Base destructor.
jotik
  • 16,015
  • 11
  • 53
  • 110
Sahib Yar
  • 947
  • 11
  • 27

5 Answers5

3

It is, but you're not calling ~Derived() directly. If you were to use

Derived *p = new Derived();
delete p;

then you'd get the error. But when you access ~Derived() indirectly via polymorphism (e.g. by calling ~Base()), then the access specifier private does not apply.

According to [class.access.virt#1]:

The access rules (Clause [class.access]) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [ Example:

class B {
public:
  virtual int f();
};

class D : public B {
private:
  int f();
};

void f() {
  D d;
  B* pb = &d;
  D* pd = &d;

  pb->f();                      // OK: B​::​f() is public, D​::​f() is invoked
  pd->f();                      // error: D​::​f() is private
}

— end example ]

And again in footnote 111 in [class.virtual]:

Access control is not considered in determining overriding.

jotik
  • 16,015
  • 11
  • 53
  • 110
3

Because destructors are called in reversed order of constructors and virtual destructor will always be called.

private has nothing to do if a virtual function is going to be called.

As I pointed here out:

Why would a virtual function be private?

ISO C++ 1998 Standard onwards explicitly states:

§10.3 [...] Access control (clause 11) is not considered in determining overriding.


A bit philosophical offtopic:

Going further this is what STL does for iostreams: Definition of Non-Virtual Interface, i.e. all public functions (with exception of destructors) are non-virtual and all virtual functions are either protected or private. Public functions call virtual protected or private ones. This gives a very clear entry point into the entire hierarchy.

Community
  • 1
  • 1
ovanes
  • 5,394
  • 2
  • 31
  • 58
0

You use a virtual destructor because you want all the destructor in your inheritance to get called. That exactly what you get. The private does not apply as you don't call the destructor explicitly.

If your destructor was not virtual you will get only Base::~Base() called. Usually that's not what you want when you have polymorphism.

neuro
  • 14,390
  • 3
  • 33
  • 58
0

You can call the destructor through a pointer to B, because it's already public there. It's the static type of the pointer which is used to determine that access in this case.

[class.access.virt/1]

The access rules (Clause [class.access]) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [ Example:

class B {
public:
  virtual int f();
};

class D : public B {
private:
  int f();
};

void f() {
  D d;
  B* pb = &d;
  D* pd = &d;

  pb->f();                      // OK: B​::​f() is public, D​::​f() is invoked
  pd->f();                      // error: D​::​f() is private
}

— end example ]

This keeps virtual functions in line with the Liskov Substitution Principle

Community
  • 1
  • 1
StoryTeller - Unslander Monica
  • 159,632
  • 21
  • 358
  • 434
0

You delete the derived class through the base class pointer. With the help of the virtual destructor you start the delete at the derived class. Because that class can access its private members, it call the private destructor. After that the base class is calling the public destructor.

Note that you call delete and not calling de destructor Derived::~Derived() direct!

T.Buys
  • 26
  • 3