[UP] [jback] [fork]

2004/05/06: C++の継承問題

 とりあえず C++ を使ってるけど、なんか嫌いだ。

 親クラス、子クラスがあるとする。親クラスの関数は子クラスから呼べるけど、親クラスの関数中では親クラスの文脈になるので、その中では親クラスの関数しか呼ばれない。子クラスの関数で上書きされていても、子クラスの関数が呼ばれずに親クラスの関数が呼ばれるのだ。つまり、子クラスから親クラスの関数をいったん呼び出してしまうと子クラスの文脈に戻れなくなる。変数は親クラスと子クラスで唯一の存在なのでこの問題はない。

 でも、仮想関数を使えば少しは問題が解決する。仮想関数は親クラス、子クラスで唯一の存在になるので、仮想関数が上書きされていれば、親クラスからでも常に子クラスの仮想関数が呼ばれることになる。そして、最初、親クラスの関数で親クラスの文脈にあったとしても、いったん子クラスの仮想関数が呼ばれれば、そこからは子クラスの文脈になってくれる。しかし、唯一の存在になったことで、上書きされた場合、親クラスの仮想関数は消滅してしまい呼ぶ手段がなくなる。

 継承されることを前提に書かれたクラスを書く場合、仮想関数でかつ親の仮想関数も呼べる手段がよく必要となる。しかし、C++ では少し工夫しないといけないのでやっかいだ。以下、その例を上げてみる。

class ClassB : ClassA {
  typedef ClassA parent_class;
  virtual function1 ();
  function1_non_virtual (); // 実態

  virtual function2 ();
  function2_non_virtual (); // 実態
}

class ClassC : ClassB {
  typedef ClassB parent_class;

  virtual function1 ();
  function1_non_virtual (); // 実態

  virtual function2 ();
  function2_non_virtual (); // 実態
}

ClassB::function2 ()
{
  function1_non_virtua2 ();
}

ClassC::function2 ()
{
  // 親クラスの元関数を呼び出す。
  ((parent_class*)this)->function2_non_virtual ();
     .
     .
  function2_non_virtual ();
}

 これによって、文脈が ClassB でも ClassC でも function2 を呼び出すと、Class2::function2 () が呼ばれ、親クラスの ClassB::function2 の実態 ClassB::function2_non_virtual () を ((parent_class*)this)->function2_non_virtual () として呼ぶことができる。でも、手間が掛かるんだな。