クラスの定義とnewによるオブジェクトの生成,メンバ関数 |
使用ソースコードをダウンロードして参考にして下さい。
●メモリ領域の獲得
「変数はどこに存在するか」と聞かれれば「メモリの中」と答えたいところです。しかし,変数は最初からメモリの中に存在しているわけではありません。
まず最初に存在するのは,変数の性質を記述した型情報だけです。その型情報に基づいてメモリ上のある領域を変数用に獲得してはじめて,変数は
メモリ上に実体として存在できるのです。このようにメモリ上に存在している変数の実体をインスタンス(instance)といいます(Fig. 2.1-(1))。
メモリ領域の獲得には,
・静的なメモリ領域確保
・動的なメモリ領域確保
の2方法があるわけですが,C言語では,前者は変数の宣言・定義によって,後者は標準ライブラリ関数malloc()などの標準関数によって行われます
(前期「ゲームソフトウェア設計論」参照)。
List 2.1は,メモリ領域の確保の典型例(C言語)です。次の3個の変数が登場しています。
・int 型のa
・person* 型のp
・person 型の無名変数
変数aと変数pは,それぞれ宣言が行われている12,13行目に処理が進んだ時点で,メモリ領域が与えられてインスタンスになります。また,15行目
では関数malloc()によってperson型の無名変数のために,動的にメモリ領域を確保しています。実は,この動的なメモリ確保の方法が,C++では大
きく改善されたのです。
・演算子new
List 2.2は,C++でList 2.1の内容を書き直したもので,分かりやすいようにList 2.1の各行に対応する内容を同じ行に書いてあります。
List 2.2の15行目を見てみると次のようになっています。
p = new person;
List 2.1の15行目,関数malloc()を使っている部分と比べると,随分と簡潔です。このnewというのはC++の演算子で,右側に型名をとって,その型の
変数のためのメモリ領域を動的に確保しようとするのです。Fig.2.2に演算子newの使い方を示します。C言語では,calloc()という配列用の領域を確保
するのに便利な標準関数がありましたが,newを使えば,配列用の領域も簡単に確保することもできます(Fig.2-(2))。
さて,演算子newの導入によって,C言語の場合と比べて改善された点として,メモリの動的確保の記述が簡単になったことがあげられます。また,機能が
標準関数から演算子に移されたために,ヘッダstdlib.hをインクルードする必要もありません。
しかし最も重要な改善点は,動的なメモリ確保の際にミスが起こりにくくなったことです。List 2.3にC言語で起こりやすいミスの典型例を示しましょう。
double型のインスタンスを生成しようと関数malloc()を使用していますが,sizeof演算子のオペランドがdoubleでなくcharになっています。
ポインタによって指されている実際のインスタンス*dptrの型charが,想定した型doubleと一致していませんから,このまま何かしらの処理をインスタンス *dptr
に施せばプログラムが異常動作を起こすことは明らかです。一方,List 2.4はList 3をC++流に書き換えたものですが,ちゃんと型の不一致として誤りが
コンパイル時に検出され,List 2.3のように危険性が黙認されることはありません。
なお,newで生成したインスタンスのメモリ領域をC言語標準関数free()で解放した場合の安全性は保証されていないので注意して下さい。
ところで,malloc()やcalloc()がメモリの動的確保に失敗した場合は空ポインタを返しました。では,演算子newがメモリの動的確保に失敗するとどうなる
のでしょう。そして,その失敗を検査する方法は? 実は,C++では“例外”というエレガントなエラー処理を可能にする機構が用意されていて,演算子newは
失敗するとこの例外の機能を使って失敗を通知します。しかし,例外の仕組みについてはLevel 9で詳しく解説しますので,しばらくはエラー検査無しに
new演算
子を使用することにします。