オブジェクト指向を実現するには,型システムはある程度柔軟でなければならない。単純なカプセル化だけであれば柔軟さは不要だが,継承や多義性を実現するうえで柔軟さが必要になってくる。

 オブジェクト指向以前のプログラミング言語では,単純な型(プリミティブ)がほとんどで,多少複雑でも配列型くらいしか使われていなかった注3)。だから逆に,完全に型を決めた方が容易だ。柔らかい型システムの言語では,実行時のプログラムのなかにメモリ管理機能が必要となる。スクリプト言語のようにもともと実行時エンジンがあるものであれば,メモリ管理は必然的に実行する。だからこそ柔らかい型システムを採用できる。しかしコンパイラ方式の場合は,もしなくて済むのであればメモリ管理機能などない方がよい注4)。

図4●ある型で定義したオブジェクトの変数には,他の型の変数も代入できる。
クラスの継承構造があるときに,継承元となるクラスの変数には,継承先となるクラスの値を代入できる

 しかしオブジェクト指向言語になって,メモリ管理が必須となった。例えば,あるオブジェクトのメンバとして,別のオブジェクトが入っている場合などがある。ウインドウを一つ表示するオブジェクトを考えてみよう。このオブジェクトはウインドウの構成によって,そのメンバとするオブジェクトは違ってくる。また,ウインドウ・オブジェクトが消滅するときは,そのメンバとなっているオブジェクトも同時に消滅しなければならない注5 )。また例えばカレンダを表示するウインドウを考えればわかるが,そこに表示するメンバの数は可変のものもある。

 またオブジェクト指向の一つの特性である多義性(polymorphism)もメモリ管理を必須とする要因の一つである。多義性は同じメソッド名でも,実際に呼び出すオブジェクトによって振る舞いを変えるというのがその基本である。このとき,共通部分でできた入れ物(変数)を用意しておき,そこに代入し得るクラスのオブジェクトを入れて使う。だから,その入れ物である変数の型は,固定ではない注6 )(図4[拡大表示])。COBOLやFORTRANでさえ「オブジェクト指向化」している現在,厳密な意味での「堅い型システム」を採用している言語は,もはやないと言っていいのかもしれない。

ポインタを使ってオブジェクト指向を実現

リスト4●多義性を利用したプログラムの例。
標準C++を使うとエラーが発生する

 堅い型システムでオブジェクト指向を実現するに当たり,重要なカギを握るのがポインタである。例えばリスト4[拡大表示]のC++のコードを見て頂きたい。一見すると問題なさそうに見えるが,実はANSI準拠のC++コンパイラであればエラーが出る注7 )。37行目でオブジェクト「aTestA」をキャストしてaClassに代入しようとすると,型の参照が正しくないというエラーがでる。これをコンパイル出来るようにするには,参照型である「rootClass&」にキャストする必要がある。参照型はオブジェクト専用のポインタのようなものだ。通常ポインタでは,それを参照して利用するときにはオブジェクトの枠組みは失われてしまい,好きなように操作できてしまう。参照型ではオブジェクトのスコープやアクセス制御を維持してくれる注8)。

 しかし話はここでは終わらない。このコードを実行すると,すべてrootClassのメソッドが実行されてしまう。多義的には動作してくれない。リストxのように,親となるクラスの変数への代入が完了した時点で,そのクラスのオブジェクトが作られてしまう。つまり,親クラスのオブジェクトが生成される。だから,多義的には振る舞わない。通常C++で多義性を実現するには,ポインタを使う(リスト5[拡大表示])。逆に言えば,C++でオブジェクト指向らしいプログラミングをするには,ポインタが必要なのだ。

 実はこの「ポインタ」,CやC++の鬼門の一つだ。これを理解し使いこなすことが,C/C++を習得するうえで重要な要素となっている。ポインタを概念的に説明すれば,その変数を格納している場所を指し示すものだ(図5[拡大表示])。C/C++ではそれがそのまま,論理メモリ空間上のアドレスを指し示している。C/C++における配列データは,先頭位置のポインタと配列要素数分の領域という形で実現している。

 ポインタ自体はその指し示すものを入れるハコを作るだけなので,別途値の実体を格納するエリアを確保してやる必要がある。これが「new」文で指示しているところだ。C/C++コンパイラは変数の生成/消滅に関しては責任を負う。だからスコープが途絶えたときに自動的にそのメモリ領域を消去する。ところがポインタを宣言してメモリ領域をプログラマが確保するよう指示している場合,そのメモリ領域は開放しない。

リスト5●標準C++で多義性を利用するためのプログラム例
 
図5●ポインタの意味。
ポインタは値が格納されている場所を指し示すものである。C/C++では論理メモリ空間上のアドレスがそのまま格納される

「正直言って,C++はよくわかんないです」
「しょうがないよ。だからこそJavaが出てきたという面はあるからね。MSワールドで行くなら,C#という手もあるし」
「そういえば,先輩も今日,C++でコード書いてましたよね。あ。まさかあれで不機嫌だったのでは」
「そぉなんだよ。最近すっかりJavaになじんでたから,久々にC++しようとするともう全然だめでさぁ。大体いちいちnewしたらdeleteしなきゃならんとか,そりゃヒープに取ってるんだからそうなんだけどさ。まったく…(以下延々と文句が続く)」
「…(こんな先輩,初めて見た)」

(北郷 達郎、八木 玲子)