継承にかかわる諸問題

「継承」はオブジェクト指向ではよく話題になり、また問題視されます。しかしそれは使い方が間違っているからです。

多重継承

あるオブジェクトが、二つ以上のオブジェクトから性質を継承するのが多重継 承です。これもよく論議のタネになります。C++にあってJavaがあえて省いた 機能でもあります。

しかし、多重継承の問題のほとんどは実装上の問題です。だから我々にとって は大きなトピックではないのです。実装の事を考えなければ、多重継承の問題 のほとんどは解決するはずです。

本来の多重継承

実は、継承を「内包の継承」に限ってしまうと、多重継承が必要になることは ほとんどありません。例えば、「犬」は「動物」です。他の何だというんです か?もちろん「哺乳類」や「食肉目」というのはあるかもしれませんが、これ らを導入したとしてもツリー状になるだけで、多重継承にはなりません。

中には、「水陸両用車」のように、一見したところ多重継承のように見えるも のもあります。しかし本当のところ「水陸両用車」とは何でしょう?「陸上で は車のように走り、水上を船のように航行できる」というものなら、陸上は車、 水上では船として見ればいいだけの話です。継承関係はその都度変えてはいけ ないなんて誰が言いました?

多重継承が必要だと感じたら、固定観念を捨ててよーく考えてみて下さい。ほ とんどの場合では使う必要はありません。もちろん、本当に必要だと感じたの なら使ってもかまいませんが。

オブジェクトコンポジション

多重継承の問題の多くは、機能の継承をしようとしている場合に起きます。他 のクラスからいろんな機能を持ってきてつなぎ合わせようとする場合です。例 えば「数字しか入力できないテキストボックス」と「文字数制限がかけられる テキストボックス」の二つを継承させて「特定の桁までの数字しか入力できな いテキストボックス」を作ろうという場合です。 もともとこのような用途にクラスや継承を使うのが間違いなのです。機能の継 承は用いてはいけません。その代わりに「オブジェクトコンポジション」を使 いましょう。

オブジェクトコンポジションは何でどう使えばいいのか?それは、変なテクニッ クを使わずに上の問題を素直に解釈することです。上の例では、「テキストボッ クス」があって、そこに「数字しか入力できない」という機能と「文字数制限 がかけられる」という機能を足せる、というものです。つまり、クラスと継承 を使って機能を足すから問題なのであって、普通に機能を足せばいいのです。

このように、機能を定義する細かい部品をくっつけてオブジェクトを構成する 手法を「オブジェクトコンポジション」と言います。この場合、もともと複数 の部品をくっつけることが前提ですから、たくさんの部品を一度にくっつけて も問題は起きないのです。

外延の多重継承

内包はほとんどの場合多重継承しないと述べました。そして機能は継承ではな くオブジェクトコンポジションで足せ、と言いました。最後に外延についての 話をしましょう。 結論から言うと、外延はいくら多重継承されても問題は起きません。なぜなら 外延というのはそのオブジェクトに属するための条件ですから、多重継承とい うのは単にその条件をANDでつなぐだけすみます。

内包の多重継承が問題なのは、それがイメージであって厳密なものではないか らです。「ワンワンと鳴く犬」と「ニャーニャーと鳴く猫」を多重継承した 「犬猫」なんて普通の人にはイメージできないでしょう。しかし外延の場合は 厳密な条件ですから、足すのは簡単です。「犬の親から産まれてきたのが犬」 で「猫の親から産まれてきたのが猫」 [1] ならば、犬と猫を両親に持つのが「犬猫」なのです。それが何と鳴こうがどん な外見をしていようが、そんなことはかまやしないのです。

このように、外延を無理に合成してしまうと内包はそれについてきません。 「犬猫」というものの定義はできたがそれが何なのかはよくわからないという 状況になるのです。この場合、「犬猫」は内包を伴わない純粋に外延だけの存 在になります。

多重継承問題は稀だ

多重継承の問題はよく(特に言語設計上の)話題となりますが、実際に問題とな ることはほとんどありません。「多重継承が欲しい」と思う場合のほとんどは 実は継承を機能の追加に使いたい場合であり、これは間違った継承の使い方で す。何度も言っているように、オブジェクトの本質は内包にあり、内包の継承 のみを使いましょう。これだけで問題は回避できるはずです。

[^1]]この定義は多少いいかげんですが許して下さい。あくまで例ですから。