The main difference is
Base * ptr = new Derived; delete ptr;
With a virtual destructor, this is legal; without it, there will be UB. dynamic_cast also requires at least one virtual function.
Therefore, if you want polymorphic behavior, use a (pure) virtual destructor. If you do not want this, use a protected constructor and do not pay service data for polymorphism (vtables). But then declare the destructor also protected to prevent deletion using the base pointer.
source share