Classについて
覚書
以下親クラス-子クラス、基底クラス-派生クラスという言葉がでてくるが、親↔基底、子↔派生で読み換え可。(混じってるだけ)
継承とvirtual
継承関係にある Base, Derived の2クラスが、同じ名前の関数func()を持っているとする。
Base *obj = new Derived()としたとき(ポリモーフィズム)
ポリモーフィズムを利用する場合は大概、派生クラスの関数のほうが呼ばれて欲しいだろうので、virtualで宣言すべきだろう
virtualでない場合、例えば親クラスの関数(子クラスでは再定義されていない)でfunc()を呼び出している場合、Derived *obj = new Derived() のようにしていたとしても、(親クラスの世界の中でfunc()をよびだしているので)Base::func()が呼ばれてしまう。virtualで宣言しておけばDerived::func()がちゃんと呼ばれる。
あえて基底クラスのほうのfunc()を呼びたければ、スコープ解決演算子を使ってBase::func() と明示的に指定して呼び出せばよい。
親クラスでコンストラクタの中で仮想関数を使うのは危険
継承した子クラスのコンストラクタが呼ばれた時、親クラスのコンストラクタ→子クラスのコンストラクタという順で呼ばれる。
親クラスのコンストラクタで仮想関数が呼ばれる時、子クラスのコンストラクタはまだ呼ばれていないので、親クラスの関数が呼ばれることになる。
つまり、子クラスでオーバーライドしているつもりの関数は呼ばれない。
ので、親クラスの中で呼ぶのではなく、子クラスのコンストラクタの中で呼び出すべき。
Initialize() みたいな関数を作った時など注意したほうがいいかも。
(仮想メンバ関数をもつ)親クラスのでデストラクタはvirtualでなくてはならない
ポリモーフィズムを利用する(Parent *obj = new Daughter() のように使う)ことを想定
デストラクタが virtual でない場合、親クラスの型のポインタを delete した際には親クラスのデストラクタしか呼ばれない
上の括弧内の例では、deleteした時に Parent *obj としているParent Classのデストラクタがまず呼ばれ、Daughter Classのデストラクタは呼ばれない
virtualをつけておくと、先に子クラスのデストラクタが呼ばれ、続いて親クラスのデストラクタが呼ばれ、結果両方のデストラクタが呼ばれることになる
コンストラクタは”下(親、基底クラス)から順に”構築していくのに対し、デストラクタはその逆順でオブジェクトを破壊していく、だそう。
基本的には継承される親クラスのデストラクタにはvirtualをつけておいたほうがよい