18

I find that almost every code snippet of virtual destructors has it as public member function, like this:

class Base
{
public:
    virtual ~Base()
    {
        cout << "~Base()" << endl;
    }
};
class Derived : public Base
{
public:
    ~Derived()
    {
        cout << "~Derived()" << endl;
    }
};

Do virtual destructors have to be public or are there situations where a non-public virtual destructor makes sense?

Joris Timmermans
  • 10,814
  • 2
  • 49
  • 75
prehistoricpenguin
  • 6,130
  • 3
  • 25
  • 42
  • @StoryTeller, except from derived type via `delete this` which sometimes make sense – Zdeslav Vojkovic Mar 20 '13 at 10:08
  • @ZdeslavVojkovic: `delete this` in the derived class doesn't require the base to have a virtual destructor though, because `this` isn't of type `Base*` in `Derived`. Other code might require that, ofc. – Steve Jessop Mar 20 '13 at 10:31
  • 1
    @SteveJessop, you are right. I haven't made it clear that was talking in context of inheritance chain, where each level can call `delete this` safely if the base one is virtual. – Zdeslav Vojkovic Mar 20 '13 at 10:35
  • @StoryTeller - you can't delete a pointer to base **if you don't have access**. There's nothing inherently wrong with making the destructor protected or private, but it restricts **who** can delete the pointer. – Pete Becker Mar 20 '13 at 11:11
  • @PeteBecker. where did I say it's wrong to make the destructor inaccessible? – StoryTeller - Unslander Monica Mar 20 '13 at 11:17
  • @StoryTeller - you didn't. You said "you can't call delete on the base", and that's wrong. – Pete Becker Mar 20 '13 at 11:18
  • @StoryTeller - can't call delete without **access**. That's not necessarily the same as "outside the class". Friends can do it, and don't have to be members. – Pete Becker Mar 20 '13 at 11:24
  • @PeteBecker, A true friend won't call delete on you... But I concede my description was lacking. – StoryTeller - Unslander Monica Mar 20 '13 at 11:29

5 Answers5

23

Do virtual destructors have to be public or are there situations where a non-public virtual destructor makes sense?

Horses for courses. You use a public virtual destructor if you need polymorphic deletion if not then your destructor does not need to be virtual at all.

Follow Herb's advice:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

In brief, then, you're left with one of two situations. Either:

  1. You want to allow polymorphic deletion through a base pointer, in which case the destructor must be virtual and public; or
  2. You don't, in which case the destructor should be nonvirtual and protected, the latter to prevent the unwanted usage.
Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 3
    But that advice assumes you'd never want to allow polymorphic deletion through a base pointer, *restricted to derived classes*. Given that the question is specifically about the motivation for virtual destructors always to be public, I think there's a gap in Sutter's justification here. The explanation could for example be, "the derived class could cast the base pointer to the correct derived type and then delete it", but that makes a few assumptions itself. – Steve Jessop Mar 20 '13 at 10:14
  • @SteveJessop: AFAIU, that is specifically the advice if you need polymorphic deletion then destructor must be virtual if not then there is no reason for destructor to be virtual at all. What are the other cases exist that need to be handled? Or maybe I misunderstood the point you are trying to make. – Alok Save Mar 20 '13 at 10:17
  • 2
    I am imagining a class hierarchy in which `delete` is always called in a leaf class, but where the thing that the leaf class wants to delete isn't necessarily an instance of the *same* leaf class, it might be a different one. Hence the base class needs a virtual destructor, and it could be protected rather than public because only derived classes of the base use it. Strange design, and probably not worth mentioning from Sutter's POV because anyone coming up with such a design can figure out the consequences for themselves. But I don't think it can be rejected as impossible. – Steve Jessop Mar 20 '13 at 10:22
  • I've just realised, my point is: "polymorphic deletion" does not logically imply "deletion by the public". That's just the *common* desired interface, and Sutter's advice assumes it to be the case without stating so. It may be that he considers `protected` polymorphism to be so niche-use as not to be worth mentioning in general advice, or it may be that my strange design didn't occur to him, or it may be that my strange design is unworkable for some reason I haven't spotted. I've never actually tried it :-) – Steve Jessop Mar 20 '13 at 10:24
  • 3
    Or what about a case where you want polymorphic deletion through a base pointer, but only in the base class itself? Then the destructor needs to be virtual, but it doesn't need to be public. For example, the base class might provide refcounting (or other memory management) for the whole hierarchy. – Steve Jessop Mar 20 '13 at 10:33
  • @SteveJessop: I understand your point now. Yes, Sutter's advice does not consider *unusual* design situations some of which you describe so aptly. It is more of an boiler plate design pattern kind of advice. I believe it assumes the fact that most of the people who would stick to this boiler plate are doing so for the polymorphic deletion while others who arrive at this situation through a rather uncanny design will be able to weigh the pros and cons by themselves. In the light of your new explanatory comments I do agree on your initial comment which talks of *gaps* in Sutter's justification. – Alok Save Mar 20 '13 at 11:21
  • Also if the base class isn't abstract, then the destructor should be only public and virtual as the class will qualify then to be instantiated with concrete objects. The protected and nonvirtual scenario wouldn't be suitable here. – Mohammed Safwat Nov 20 '17 at 08:37
6

Just as non-virtual destructors, no they need not be public, but most of the time they are.

If your class is an exception to the rule and needs to take control of the lifetime of its instances for any reason then the destructor has to be non-public. This will affect how clients can (or cannot) utilize instances of the class, but that's of course the whole point. And since the destructor is virtual, the only other option would be virtual protected.

Related: Is there a use for making a protected destructor virtual?

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
  • @ChristianSeverin: I simply used the same word as the question did. But a small edit makes things better, thanks for the tip. – Jon Mar 20 '13 at 10:01
  • And (I think) you can rule out a `private virtual` destructor, because a base class with a private destructor can't be destroyed at all. A private destructor might make sense for a class not intended to be a base, but if it's not a base then there's no point it being virtual. – Steve Jessop Mar 20 '13 at 10:19
  • @SteveJessop: That's what I think too ("the only other option would be `virtual protected`"). – Jon Mar 20 '13 at 10:25
  • @Jon: yes, I'm trying to fill in the reasoning for that statement, i.e. rule it out explicitly rather than implicitly by not mentioning it :-) – Steve Jessop Mar 20 '13 at 10:28
2

If you plan to create/destroy objects via special methods (for example, create/destroy), it is not necessary. But if you create your object on stack or heap, you have to have public destructor.

AnatolyS
  • 4,249
  • 18
  • 28
1

The question here is about a virtual destructor, hence I assume the permutations of reasons on why such implementation is needed should include inheritance cases as well. The answer for the question depends on the following:

1) You may use a private constructor/destructor if you don't want class to be instantiated. Though, The instantiation can be done by another method in the same class. So, when you want to use a specific method like MyDestructor() within the class to call the destructor, a destructor can still be put under private. For Ex: Singleton design pattern. Also, in this case, it prevents the class from being inherited

2) If at all the class is intended to be inherited, Private base class destructor cannot be allowed (throws a compile error).But, a protected base class destructor allows inheritance

3) The type of inheritance (public and protected) of a protected virtual destructor allows a safe way of multi level inheritance A->B->C so that when the destructor of C is called, the memory is cleaned up better.

4) A private destructor alone cannot allow delete for (I'm not sure about the auto_ptr, but I think even that should adhere to the same thought of using a "private" destructor) when the memory is dynamically allocated using new.

All around, I see using a private destructor may be error prone, especially, when someone who's not aware of such implementation is about to use such a class.

protected and public destructors are always welcome and the usage depends on the needs as given above.

Hope this clarifies.

uniqrish
  • 1,750
  • 1
  • 11
  • 7
0

There are two separate rules involved here. First, if your design calls for deleting objects of a derived type through a pointer to a base, the destructor in the base must be virtual. Second, if a member function (and by that I broadly include the destructor) is protected or private, then the contexts in which it can be called are more restricted than when it's public (of course, if the destructor is private, you can't derived from the class). For example:

class C {
protected:
    virtual ~C();
    friend void destroy_me(C*);
};

void destroy_me(C *cp) {
    delete cp; // OK: destructor is accessible
}

void destroy_someone_else(C *cp) {
    delete cp; // Error: destructor is not accessible
}
Pete Becker
  • 74,985
  • 8
  • 76
  • 165