Mix-Inが必要な理由

注:ここでは"Mix-In"を言語仕様ではなく、Mix-In本来の語義である「仮想継承時の約束事」という意味で使っています。

 クラスX、Y、Zを、ポリモーフィズムクラスとして使いたいとします。このクラスはメソッドA,B,Cを実装する必要があります。通常であれば、メソッドA,B,Cの宣言を持つインターフェイスクラスI(C++では純粋仮想クラス)を作成し、ここからX,Y,Zを派生させて使います。

 さて、クラスX、Yの内、メソッドのA,Bの実装が全く同じだったとします。当然コードを共有したいですよね。しかし、インターフェイスクラスには実装が書けません(C++では可能ですが、ここでは置きます)。通常の解決策はメソッドB,Cの実装を書いたクラスImpleを作成し、クラスX,Yに集約として持たせます。

 そして、X::A(),Y::A()がImple::A()を、X::B(),Y::B()がImple::B()を呼び出すようにします。これを「Impleの機能をX,Yに委譲する」と言います*1。これによって、A(),B()の実装が共有されます。ちょっと考えればわかりますが、メソッド数が増えると非常にめんどくさい作業になります*2

 そこで、A(),B()のメソッドを持つMix-InクラスMを作り、これをクラスX、Yに継承させる事にします。これなら、委譲コードを記述する必要がありません。ところが、これだとI::A(),I::B()とM::A(),M::B()が競合してしまって、コンパイラが通りません*3

 結果として、クラスX、Yは以下のように全く同じ継承を持っているにも関わらず、ポリモーフィズムを使ってインターフェイスを共有することが出来ないという現象が発生ます。

  • IとMを継承したクラスX(メソッドA(),B(),C()を持つ)
  • IとMを継承したクラスY(メソッドA(),B(),C()を持つ)

また、以下のクラスも、X、Yと公開するメソッドは同じ筈なのに、やはり共有することが出来ません。

  • Iを継承したクラスZ(メソッドA(),B(),C()を持つ)

 残念ながら、C++ではこれを解決する手段がありません*4。近代的な言語であれば、Mix-Inを言語仕様として採用する事でこの辺の解決手段が用意しています。例えば、2カ所から継承したメソッドを繋ぎ変える構文(インターフェイス名のエイリアシング)とか、Mix-Inを特別な継承形式と捕らえる(RubyのModule構文)とか。

 これ、一つ疑問なのは、静的な言語では解決不可能なのかな? 、と。
 どうなんだろう……。よくしらない
 

*1:配管コードとか言う事もあるかな?

*2:最近のIDEではこの委譲コードを自動生成する機能があるようですが、みはえるには本末転倒に感じます

*3:いや、コンパイラは通るかな? でもIはインターフェイスクラスとしては役に立たなくなります

*4:メタプログラミングを用いて擬似的に実現する方法はあるみたいです。ただいま検証中なんですが、さっぱりコードが読めなくて僕の手に負えません^^;