デストラクタはpublicかprotectedかという話の補足
「C++のクラス作ったら、絶対にデストラクタをvirtual宣言しなさい」に対するエキスパートの意見
これにこんなことが書いてある。
protected なら non-virtual
デストラクタは基本virtualでpublicにすべきだが例外としてnon-virtualでprotectedでもいいと。
一体どんなケースなんだと読み進めると
「デストラクタを protected にして non-virtual」というのであっています。More Exceptional C++ の項目27 参照。
当該項目にはこう書いてある。
第一に、具象クラスからの派生は常に回避すべきである。基本クラスが具象クラスではない場合、つまり基本クラスのインスタンス化のためにpublicなデストラクタが不要な場合、(a)基本クラスのポインタを介したポリモルフィックな削除を許可するか(デストラクタは仮想かつpublicでなければならない)、(b)削除を許可しないか(デストラクタは悲仮想かつprotectedでなければならない)のどちらかになる。後者の理由は望ましくない使用を防ぐためだ。詳細に関しては[Sutter01]を参照してほしい。
じゃあその望ましくない使用って何なのよ。肝心の参照先は以下の記事。
Virtuality This article appeared in C/C++ Users Journal, 19(9), September 2001
Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.
このブロックのunary_functionのサンプルコードが答えのようです。
template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; // Example 4: Illegal code that you can assume // will never exist. // void f( std::unary_function* f ) { delete f; // error, illegal }
上記のfにunary_functionの派生クラスを渡してもdeleteでは期待しているデストラクタは呼ばれないし実際は落ちないかもしれないけど(手元のcygwin g++ 4.3.4では落ちない)仕様的には未定義な動作で
unary_functionがprotectedな空定義のデストラクタを持っとけばコンパイルエラーで不正使用を防げるのにという話。サッターさんも将来標準がそうなってくれるやもと書いてる。
結局はてブにもリンクのある
C++では基底クラスにvirtualデストラクタを書こう
ある程度の経験?
にもつながる。
こういうC++のいやあな部分を全て回避すれば、C++は素敵な言語になる。素敵なC++の使用方法としてはSymbianOSの流儀が一番しっくりくると思っている。
SymbianではCBaseというクラスがあって、一般的なクラスはみんなこいつから派生させるルールになっている。CBaseはvirtualなデストラクタを定義している。
ところでMore Exceptional C++ の項目27のメインは本件とは関係のないDieDieDie()という関数にある。
いろいろな死に方が書かれている。最初の記事のリンク先にはなくて本には載っているのを抽出。特に二つ目は面白い。
void DieDieDie() // ヌルデータポインタに書き込むC++の方法 { *static_cast<char *>(0) = 0; } void DieDieDie() // 存在しないヌル関数ポインタを呼び出すC++の方法 { static_cast<void(*)()>(0)(); }
あと、デストラクタに限らず全てのメソッドを何でもかんでもvirtualにするのはアリだと思う。テスタビリティが俄然違う。
このクラスのこのメソッドが失敗したときの挙動が見たい。細かく制御したい。そこで一時的にスタブに差し替えてテストしたい、というときにvirtualでないメソッドがあるクラスだとなんともやりようがない。まさかテストでライブパッチ当てるとかありえんし。
javaみたいに全部オーバーライドできるようにしとくのがあとあとメンテナンス性が上がるんじゃなかろうか。