I have a class which is abstract in that it defines common behaviour for concrete classes. As such, there is going to be no memory to clean up because the class cannot be instantiated. However, I am aware that you need a virtual destructor in order for the derived destructors to get called if their static type is the Base class.
Does this mean I should declare a virtual destructor for an abstract class always, but just leave the implementation empty?
You must provide a definition of every destructor in a class hierarchy, since all destructors up the inheritance graph do get called when a derived class is destroyed, even if some of the destructors are trivial.
Typically, you achieve this by putting virtual ~Base() { }
(or some exception-specified variation thereof) in your base class. However, if the destructor is the only virtual member function and you want to make the base abstract, you can make the destructor pure-virtual, but you still have to define it:
struct Base
{
virtual ~Base() = 0;
};
Base::~Base() { }