0

I have Y-shaped class hierarchy: class C inherits from A and B, and class D inherits from C. A and B have virtual destructors and C's destructor is not virtual. I know that if there is no double inheritance (say no B) ~C() will be virtual. My question is does double inheritance affects it?

class A { virtual ~A(); ...};
class B { virtual ~B(); ...};
class C : public A, public B { ~C(); ...};
class D : public C { virtual ~D(); ... };

I have to delete instances of class D through a pointer to C.

C* c = new D;
delete c;

I suspect that there are some corner cases where ~B() is not executed - is it possible? Can it depend upon level of optimizations? Should definition of to D present in .cc file where 'delete c' is called?

All destructors except ~B() are nops, class C is empty class: no data members, no functions, just a trivial constructor and an empty destructor. I wrote several test programs in all cases ~B() was executed, but I am sure I did not try all the possible combinations.

uuu777
  • 765
  • 4
  • 21
  • 1
    It will be good that you share your mind why you think there could be a corner case – Adrian Shum Jan 18 '19 at 02:21
  • Picky point: Your code doesn't actually show `D` as inheriting from `C`. – ShadowRanger Jan 18 '19 at 02:33
  • 1
    Possible duplicate of [Are virtual destructors inherited?](https://stackoverflow.com/questions/2198379/are-virtual-destructors-inherited) (Not an exact duplicate, but it contradicts your belief that `C`'s destructor could be non-virtual) – ShadowRanger Jan 18 '19 at 02:33

3 Answers3

2

C destructor is implicitly virtual since at least one of its base destructor is virtual.

Thus because C destructor is virtual and you delete through a pointer to C, D destructor would be called.

If neither A or B destructor would be virtual, then it would be undefined behavior to delete a D object but this is not the case here.

If a class C derive from class(es), then it knows how to destroy its base classes. Thus B destructor would always be called (assuming that you delete either the final object or from a level where the destructor is virtual either explicitly or implicitly.

In practice, even in the undefined case (only D destructor is virtual and object is deleted through C pointer), B destructor would probably have been called but D part would not have been properly destroyed. But since, it is undefined, you cannot rely on that.

Phil1970
  • 2,605
  • 2
  • 14
  • 15
1

C's destructor is not virtual.

Yes it is. It has base(s) with a virtual destructor(s), so the destructor of C is implicitly virtual. Whether the destructor is declared virtual explicitly or not is irrelevant. Same goes for destructor of D.

I have to delete instances of class D through a pointer to C.

I suspect that there are some corner cases where ~B() is not executed - is it possible?

As long as C's destructor is virtual, there is no problem. If C's destructor wasn't virtual, then deleting a dervied object through a pointer to C would have undefined behaviour.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `If C's destructor weren't virtual, then deleting a dervied object would have undefined behaviour.` : from my understanding, it is well defined isn't it? Virtual destructor affects the case when you delete a base class pointer pointing to derived class instance. Without virtual, base class' destructor will be called. With virtual, destructor of the actual type of the instance will be called. This is just like normal virtual method. – Adrian Shum Jan 18 '19 at 02:42
  • @AdrianShum you seem to be reading an incomplete version of the answer. `through a pointer to C` is an essential part of the sentence. In that case behaviour is undefined indeed unless destructor of C is virtual. – eerorika Jan 18 '19 at 02:48
  • That's what I mean: if deleting through a `C` pointer (i.e. pointer to bas class) which points to `D`, if `~C` is non-virtual, compiler will call `~C()` (although the consequence is undefined), while if `~C()` is virtual, `~D()` will be called – Adrian Shum Jan 18 '19 at 03:09
  • `compiler will call ~C()` no such guarantee. The behaviour is undefined. (but i would not be surprised to observe that behaviour in practice) – eerorika Jan 18 '19 at 09:33
0

As far as I know, destructor chaining has nothing to do with virtual destructor. As long as destructor of certain class is invoked, it will automatically invoke the base class desctructors for you.

What Virtual-ness of Desctructor come into picture is when you are deleting a derived class instance through a pointer of base class.

In your above example, assuming ~C is not virtual (i.e. you are not declaring virtual for any destructor), and if you are deleting a D instance through a C*, desctructor of D could have been missed, and compiler is going to call ~C for you instead. As mentioned above, calling ~C is going to cause all base class destrcutors (~A & ~B) to be called automatically.

However, given you have already declared destructor to be virtual in base class (A etc), virtual-ness will propagate to all derived classes' destructor. Which means, even you have not declared ~C as virtual, it is actually virtual.

Adrian Shum
  • 38,812
  • 10
  • 83
  • 131