派生される可能性があるクラスではデストラクタを virtual にすることは C++ の基本事項としていいでしょう。しかし、その知識を持ってはいるけどいまいち virtual を理解していなくて、何でもかんでも virtual にしてしまう、というのではいけません。そういう人のために、ここでは virtual を使ってはいけない場合について書きます。
さて、メンバ関数を virtual 宣言すると、そのクラスに対し vtable と呼ばれるテーブルが作られ、隠しメンバとして vtable へのポインタが追加されます。vtable は virtual 宣言されている関数のアドレスを集めたテーブルであり、vtable へのポインタは 32bit 環境なら大抵 4 byte になります。つまり、クラスの中に virtual 宣言されたメンバ関数があると、クラスのサイズは 4 byte 増えることになります。そのため、virtual が必要ないクラスでは virtual 宣言しないことにより、virtual 宣言した時と比べて 4 byte 節約できる計算になります。
virtual キーワードがあるのは、このようにコストを減らせるようにするためです。int 型のデータメンバを1つしかもたないようなクラスでは、virtual にした場合、virtual にしないのと比べてコストが2倍になります。これはかなり大きな違いです。
それだったらデフォルトで virtual にして、non-virtual を指定できるようにした方が親切なような気がしますが、そんなこと言ってても C++ の仕様は変わらない(今更この部分を変えたら大変なことになる)ので、諦めます。
virtual を使うと、基底クラスのポインタから派生クラスの関数が呼び出せるようになります。ということは、基底クラスのポインタから派生クラスの関数を呼び出したくない時は virtual を指定してはいけない、ということになります。そんなことがあるのか、と疑問に思う人もいるかもしれません。それなら、基底クラスの関数を派生クラスの関数によってオーバーライドされたくない時がある、といえばわかり易いかもしれません。オーバーライドによって振舞いを変えられてはいけない場合は結構あります。
その明らかな例は private な関数です。private な関数はそのクラスからだけ呼ばれることを考えて作られているし、呼ぶ側もオーバーライドされることは考えていないのが普通です。しかし、その関数をうっかり virtual 宣言してしまい、不幸なことに Derived の作者がたまたま同じ名前の関数を作ってしまった場合、勝手にオーバーライドが起こり、予期せぬ結果が起こるでしょう。
private でなくてもこのようなことは起こり得ます。private でなければ、Derived の作者がたまたま同じ名前の関数を作る可能性は減りますが、意図的にオーバーライドしようとすることはあるかもしれません。
というわけで、virtual を指定するのは、オーバーライドされて良い関数なのかどうか考えてからにしましょう。Java の final や Eiffel の frozen のように、オーバーライドを禁止するキーワードが C++ にもあればもっといいんですが、ないものは仕方ありません。今できることは、オーバーライドされてよいもの以外は virtual にしないようにすることです。