Virtual Default Destructors in C++
Asked Answered
T

4

25

I've got a large set of inherited classes (criteria) which inherit from a base class (criterion). Here's criterion's code

class criterion
{
public:
    virtual unsigned __int32 getPriorityClass() const = 0;
    virtual BOOL include(fileData &file) const = 0;
    virtual void reorderTree() = 0;
    virtual unsigned int directoryCheck(const std::wstring& directory) const = 0;
    virtual std::wstring debugTree() const = 0;
};

Some examples of derived classes from this one:

class fastFilter : public criterion
{
public:
    void reorderTree() {};
    unsigned int  directoryCheck(const std::wstring& /*directory*/) const { return DIRECTORY_DONTCARE; };
    unsigned __int32 getPriorityClass() const { return PRIORITY_FAST_FILTER; };
};

class isArchive : public fastFilter
{
public:
    BOOL include(fileData &file) const
    {
        return file.getArchive();
    }
    std::wstring debugTree() const
    {
        return std::wstring(L"+ ISARCHIVE\n");
    };
};

Since I don't have a destructor here at all, but yet this is supposed to be a base class, do I need to insert an empty virtual destructor, I.e. like this?:

virtual void ~criterion() = 0;

If that virtual destructor declaration is needed, do all intermediate classes need one as well? I.e. would fastFilter above need a virtual destructor as well?

Traipse answered 5/5, 2009 at 22:28 Comment(1)
The above is not an empty destructor. It's a destructor that is also a pure virtual function. This has nothing to do with being empty, and in fact the destructor is special in that it must always have a definition even when it's pure virtual.Ludly
I
53

Yes - the base class needs a virtual destructor, even if it's empty. If that is not done, then when something delete's a derived object through a base pointer/reference, the derived object's member objects will not get a chance to destroy themselves properly.

Derived classes do not need to declare or define their own destructor unless they need something other than default destructor behavior.

Inspan answered 5/5, 2009 at 22:31 Comment(1)
why not mark it as default? Instead of "= 0" put down "= default"Bassett
J
33

The recommendation is to insert:

virtual ~criterion() {}

Starting from C++11, you can use = default; instead of an empty body {}.

This is to avoid problems with deleting from a base class' pointer. Otherwise you will leak memory as derived classes' destructors will not be called.

criterion *c = new fastFilter();
delete c; // leaks
Jade answered 5/5, 2009 at 22:32 Comment(5)
Is there any reason to use an empty destructor over a pure virtual one?Traipse
Isn't virtual ~criterion() noexcept {} prettier?Cathryncathy
@user1095108, isn't virtual ~criterion() = default prettier?Winburn
@user35443: the "=default" didn't exist in 2009. It is something added in C++11. Yes, nowadays I think that would be the preferred option.Goodwin
@Goodwin Ah, it appears so that three years ago I didn't notice the answer had been written in '09. Geez, time flies...Winburn
K
13

You don't need to make the destructor abstract, just give it a empty implementation:

virtual ~criterion() { }

This way you are not forced to implement it in every child class, but still each of them will have a (inherited) virtual destructor.

Kannada answered 5/5, 2009 at 22:34 Comment(0)
A
7

One small change from what others have already answered:

Instead of

virtual void ~criterion() = 0;

the required version is:

    virtual ~criterion() {}  //Note: Removed void as destructors not allowed 
                             //  a return type

To know more about virtual destructor have a look at this link from FAQ When should my destructor be virtual?

Auld answered 6/5, 2009 at 4:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.