基底クラスには仮想デストラクタをもたせよう 14項

今日はとても大事な話なので、結論から

  1. 基底クラスとして使うであろうクラスは、デストラクタを必ず virtual とする
  2. 基底クラスとして使わない(継承するつもりがない)クラスは、デストラクタをvirtual にしない。


なぜか?

1.について

Class BaseHige 
{
public:
    BaseHige();
   ~BaseHige();
};

Class SuperHige : public BaseHige 
{
public:
    SuperHige();
   ~SuperHige();
};


のような継承関係があるとして

BaseHige* basePtr = new SuperHige();
delte basePtr;


とした場合、BaseHige, SuperHige両方のデストラクタが呼ばれることを期待しているのだが実際はそうはならない。


基底クラスのポインタを介しての delete では、基底クラスにVirtualでないデストラクタがあると、その結果は不定扱いなのである。
不定なのでたとえば、派生クラスのデストラクタが呼ばれないなどが起こる可能性があるからまずい、という話。
これはC++の基本であり、肝に銘じている人は多いと思う。

2について

ところがこれには罠があり、何でもかんでもデストラクタを virtual にすればよいという話ではなくて、継承をしない前提であれば virtual にするべきでないと書かれている。


それはなぜかというと、 virtual にした時点で仮想関数テーブルが作られてしまい、オブジェクトのサイズが2倍になってしまい可搬性が失われてしまうからだそうです。
書籍内では short int メンバーのx, y を持つ Pointクラス(継承して使わないもの)について触れられていて、virtual がなければ16bit * 2 = 32bit構造体として扱えるのに、virtual をつけるとサイズが倍になってしまい可搬性がなくなってしまうと書かれています。


私の場合、後者の理解が足らず、とりあえずデストラクタを virtual にしておけ作戦でやっていたのでそこが反省点です。
無駄に仮想関数テーブルが作られるのがだめというのは分かりますが、サイズが増えるので可搬性がなくなるというのは「うーんどうだろう・・・」という感じです。