オブジェクト指向はどこに向かうか
オブジェクトとポインタ
C++のようにC言語風の構文を持つオブジェクト指向言語はいくつかあります。C言語にオブジェクト指向の機能を導入した言語としては、Mac OS XやiPhoneのアプリケーション記述言語であるObjective-Cがあります。JavaとC#はともにC++のよい点を取り入れて設計された言語と言われています。さて、これらの言語で、オブジェクトとポインタがどのように扱われているかを見てみます(図2)。
前ページの例で示したように、C++ではインスタンスオブジェクトは構造体のようにその実体が変数に格納されていても、メモリ上のどこか(ヒープ領域)にあってそれをポインタで参照していてもよいことになっています。structという予約語のほかにclassという新しい予約語でクラス定義を記述することができますが、どちらを使ってもインスタンスの扱いは同じです。
Objective-Cの場合、インスタンスはヒープ領域に動的に確保する方法しかありません。構造体はC言語と同じように扱えますが、Objective-Cではstructはオブジェクトを定義する方法ではありません。
C#はstructとclassを持っていますが、structはスタック上の自動変数にインスタンスの実体を作成することができます。classを使った場合はインスタンスはヒープにとられます。
Javaの場合、structは存在せず、インスタンスはヒープにとられます。
Javaにはポインタがない、というキャッチフレーズを聞いたことがあるかもしれません。Javaではインスタンスはヒープに作成されますので、ヒープのアドレスを参照しているという意味ではポインタは使っています。しかし、ヒープに作成される以外の形態のインスタンスがないため、「ポインタで指されたオブジェクト」ということを意識することはありません。
また、C言語などでは、T型のデータがあれば派生型として*T型(T型を指すポインタ型)が自動的に存在する言語仕様になっていますが、Javaにはそのような意味でのポインタや、さらにポインタ演算もありません。そのような意味においては、Javaにはポインタはないと言えます。
インスタンスの生成と解放
C++、Java、C#では、インスタンスオブジェクトを初期設定するための手続きをコンストラクタと呼び、通常のメンバ関数とは違う扱いをします。ほかの言語でも通常のメソッドとは扱いが異なる場合が多く、イニシャライザと呼ばれることもあります。
一方、インスタンスを解放する時に実行される手続きを同様にデストラクタと呼びます。ほかの言語ではファイナライザと呼ばれることもあります。
インスタンスオブジェクトはプログラムの実行に伴って動的に次々に作られていきますが、一方で、役目が終わったインスタンスはきちんと解放して再利用できるようにしなければなりません。このために、JavaやC#をはじめ、最近設計された多くの言語にはガーベジコレクション、つまり「ごみ集め」の機能があります。使われなくなったメモリ領域を自動的に解放してくれるので、メモリリーク(メモリの解放し忘れ)がほとんどなくなり、プログラミングも容易になります。
一方、ガーベジコレクションは実行効率を低下させる要因になりますので、C++には今のところ、言語仕様の上でガーベジコレクションの機能はありません。スタック上や静的変数にインスタンスが存在することを許していることもその理由だと考えられます。
Objective-Cは、生成したインスタンスをリファレンスカウンター方式で管理しています。あるオブジェクトが何カ所から参照されているかをプログラマの責任で管理する方式で、実装は容易で実行も高速ですがメモリリークが起きやすいという欠点があります。新しい言語仕様(Objective-C 2.0)ではガーベジコレクションも利用できるようになっていますが、リファレンスカウンター方式とガーベジコレクションの併用はできません。また、現時点では iPhone上でガーベジコレクションは利用できません。