ネタ元:『Modern C++ Design』雑感 - スーパー/サブクラス?@Faith and Brave
C++では「スーパークラス」「サブクラス」という呼び方は推奨されていないはず(『C++の設計と進化』でBjarne氏が言っている)
理由はもちろん、派生したクラスの方が多機能だからだ
C++では「基底クラス」「派生クラス」って言いますね。この呼び方の是非はさておいて、ここではこのC++用語を使いましょう。
Javaでは「スーパークラス」「サブクラス」って言います。C#のbaseにあたるキーワードもJavaではsuperですね。
派生クラスの方が多機能なのに、どうして機能の少ない方が「スーパー」なの?
その疑問はごもっとも。というわけでちょっと解説してみましょう。
先日のオブ熱イベントでも言いましたが(これ引っ張るなぁw)、クラスとはオブジェクトの集合だと考えられます。
集合にとっての「スーパー」、すなわち「スーパー集合」「すごい集合」とは何でしょう?
一言で言えば「デカいこと」、つまり、含むものが多い集合の方が、より「スーパー」です。
日常的にも、「Windows Vista Home PremiumはHome Basicのスーパーセットだ」とか言いますよね。
集合ってのは英語で言えばセットですから、スーパー集合はスーパーセットです。
ちなみに、逆の表現をすれば、「Home BasicはHome Premiumのサブセットだ」となります。
「スーパーセット」「サブセット」というのは集合論の用語でもあり、「セット」を「クラス」に置き換えれば、そのまま「スーパークラス」「サブクラス」になります。
さて、このたとえ話はよけい事態をわかりにくくしてしまったでしょうか?
Windows Vistaの例を用いれば、確かに機能が多い方が「スーパー」ですね。
Windows Vista自体をひとつの集合と見るならば、それは「機能の集合」と言えます。
ということは、多機能ならばそれだけ含むものが多い集合なのですから、スーパーセットなのです。
ここで発想の転換です。「機能」は忘れてしまいましょう。
Vistaについてもそうです。一段階抽象化して、「多機能だからスーパー」ではなくて「含むモノ(Vistaで言えば機能)が多いからスーパー」と考えます。
クラスの関係についても抽象化して考える必要があります。
クラスを集合として捉えるならば、派生クラスは基底クラスを含む集合です。
基底クラスの方が低機能だとすると、「低機能なものは、高機能なものを含む」となってしまいます。変ですね。
基底クラスは、機能が「少ない」のではなく、「曖昧」なのです。
派生クラスは機能が「多い」のではなくて、より「具体的」なのです。
正しい関係は、「機能が有るかもしれないし無いかもしれないものは、機能が有るものを含む」です。
基本的に、クラスの継承関係は、機能の多寡ではなく、その曖昧性/具体性で決まるのです。
なお、数学では、クラスの特性を「内包」といい、そのインスタンスを列挙したものを「外延」と言います。
内包が具体的な(情報量が多い)ほど外延は少なく、内包が曖昧(情報量が少ない)ほど外延は多くなります。
具体例を出しましょう。
クラスはインスタンスの集合ですから、より多くのインスタンスを含む方をスーパークラスとします。
毎度おなじみSystem.Windows.Forms名前空間のControlクラスとButtonクラス。Controlの方が基底クラスです。
さて、ControlとButtonでは、どちらがインスタンスの数が多いでしょうか?
実際には、メモリが許す限り作れるのでしょうから、数を数えてみるというのは現実的ではありません。
しかし、継承関係を考えれば、Button以外にも、TextBoxもLabelもFormも、全部Controlクラスのインスタンスの一種です。
ここから、Controlクラスの方が、含むインスタンスが多いことは明らかですね。
よって、Controlの方がスーパークラスなのです。
余談ですが、仮にメモリの容量が無限にあったとして、無限個のButtonのインスタンスと無限個のControlのインスタンスがあったとしたら、どっちのほうが多いのでしょう?
この場合は、数学の言い方では、「Controlの方が濃度が大きい」ということになる…のかな? 自信ありません。
では、機能の多寡に着目したらどうでしょうか?
Control c = new Button();
Button b = new Button();
さて、cとbでは、どちらの方が機能が多いですか?
インスタンスが同じなのに、キャストするたびに機能が増えたり減ったりするというのはおかしな話ですから、機能の多寡は、一概にクラスでは決まらないということがわかるでしょう。