The purpose of virtual destructor (i.e. the purpose of making a destructor virtual) is to facilitate the polymorphic deletion of objects through delete-expression. If your design does not call for polymorphic deletion of objects, you don't need virtual destructors. Referring to your example, if you'll ever have to delete an object of type B
through a pointer of type A *
(polymorphic deletion), you'll need virtual destructor as high up in the hierarchy as A
. That's how it looks from a formal point of view.
(Note, BTW, as Neil said, that what's important is how you create/delete your class objects, not how classes manage their internal memory.)
As for the good programming practices... It depends on your intent and your design in the end. If your classes are not designed to be polymorphic at all (no virtual methods whatsoever), then you don't need virtual destructors. If your class is polymorphic (have at least one virtual method), then making the destructor virtual "just in case" might be a very good idea, and in this case it bears virtually zero performance/memory penalty with it.
The latter is usually expressed as a rather well-known good practice guideline: if your class has at least one virtual method, make the destructor virtual as well. Although from the formal point of view a virtual destructor might not be really needed there, it is still a pretty good guideline to follow.
Classes that have no resources but can form polymorphic hierarchies should always define empty virtual destructors, except that it is perfectly sufficient to define an explicit empty (and even pure) virtual destructor at the very base of the hierarchy. All other destructors will become virtual automatically, even if they are defined implictly by the compiler. I.e. you don't have to explicitly define an empty destructor in every class. Just the base is enough.