データ型とポリモーフィズム
何がオブジェクトか?
「第1回:オブジェクト指向、再考」では、オブジェクトについて、概念的な説明を試み、C++による簡単な定義例で雰囲気をつかんでもらいました。ただ、オブジェクト指向には実にいろいろな考え方があり、「○○は△△だ」とすっきり断言できない事情があります。
オブジェクト指向の世界の大御所的な存在に「Smalltalk」があります。Smalltalkは1980年代のオブジェクト指向ムーブメントのきっかけを作った言語システムであり、現在もVisualWorksやSqueakなどの多くの環境で触れることができます。このSmalltalkでは、整数や真偽値、条件分岐や繰り返しに用いるブロックまで、ほぼあらゆるものがオブジェクトです。
最近人気の高いRubyは国産のオブジェクト指向言語で、その対抗馬としてよく比較される言語にPython(パイソン)があります。これらはインタプリタで動作するスクリプト言語ですが、これらの言語でも整数などのデータ型はオブジェクトとされています。
C++やObjective-Cでは、整数などのデータはオブジェクトではありません。JavaやC#でも、整数などの基本データ型はオブジェクトではありませんが、オブジェクトとして扱えた方が便利な場合が多いので、基本データとオブジェクトの間で変換を行えるようになっています。これをボクシングとアンボクシング、文脈によって自動的に変換を行う機能をオートボクシングと呼びます。
つまり、言語の美しさや統一感、プログラムのしやすさを第一に考えると、どれもこれもオブジェクトである方が扱いやすいわけですが、実際の処理効率やデータ表現といったことを考えると、少なくとも基本データ型はマシン表現に近い方がいいということになるわけです。
配列に関する取り扱いもまたさまざまです。C言語風の考え方もあれば、大きさ(容量)を動的に変化できる配列もあります。配列がオブジェクトとして扱われる言語も、そうでない言語もあります。
さらに、クラスをオブジェクトとみなす言語もあります。SmalltalkやObjective-Cでは実行中のメモリ内に、オブジェクトとして動作するクラスが実体として存在し、これをクラスオブジェクトと呼びます。クラスオブジェクトは、クラスに属するインスタンスに共通する属性の操作や、インスタンスの作り方に動的にかかわることができます。クラスオブジェクトの話題は実は奥が深いのでこの辺で切り上げておきます。
メッセージはどうやって送るのか
オブジェクト指向言語では一般に、あるオブジェクトのメソッドを起動する動作を「メッセージを送る」と言います。ただ、C++では「メンバ関数を呼び出す」という言い方を使うようです。図1に、いくつかの言語のメッセージの送り方を示します。BirthdayというクラスのメソッドsetDateを呼び出しますが、このメソッドには引数が2つあるとします。
まず(1)はC++です。(2)はJavaで、newの関数名の後のカッコは、コンストラクタの呼び出しに引数がないことを表しています。(3)はRubyです。ここまではオブジェクトの後にピリオド、メソッド名を書くグループです。図にはありませんが、C#も同じです。
(4)はSmalltalkです。縦棒の間に名前を書いて、変数であることを示します。オブジェクトの後に空白を置いて、メッセージ名を書きます。メソッド名をちょっと変えて、setMonth:day:としています。引数がある部分をコロン「:」で示します。
(5)はObjective-Cですが、この言語はSmalltalkからいろいろな要素を受け継いでおり、メッセージの送り方も似ています。メッセージ送信はカギ括弧で囲んだ中に、受け手のオブジェクトとメッセージ名、引数を書き、全体は式となります。引数が複数個ある場合、何番目の引数が何を意味するのか忘れてしまうことがよくありますが、(4)、(5)の流儀では引数の意味がはっきりするので助かります。読みやすいかどうかは好みが分かれるかもしれません。
また、x.add(y)と書く代わりに、演算子がメソッドの呼び出しを表すように定義することでx + yのように記述できる言語もあります。これを演算子のオーバーローディングと呼びます。C++、Smalltalk、Rubyではそのような定義が可能です。