配列インスタンスと多態性

C++ において、クラス Class の配列インスタンスは、
 
new Class[n];
 
のように、new[] オペレータで取得する。当然、これを、
 
Class* p=new Class[n];
 
と受け取ったあと、
 
delete [] p;
 
のように、delete[] オペレータを使ってこれを解放するのが常套手段である。
さて、もし、Class が、 仮想クラス DerivedClass の継承だったとする。当然ながら、
 
DerivedClass* p=new Class;
 
と受け取ることで、*p は多態性オブジェクトとして振る舞うのだが、問題となるのは、
 
DerivedClass* p=new Class[n];
 
とした場合である。やってみたことがある人間であればわかるように、これは重大な問題を持つ。
結論から言ってしまえば、インスタンス配列を生成する new[] オペレータを使っても良いのは、POD に限る。
 
もちろん、デフォルトコンストラクタが定められている非仮想クラスに関しては、
インスタンス配列を生成する応用を考えてもいいかもしれないが、
上のように多態性を実現することはできない。考えてみれば分かると思うが、
配列ってのは、連続する記憶領域を確保するものであり、上のようにしたとき、
 
p[0];
 
のサイズは DerivedClass のものに一致する。当然、Class の方が DerivedClass 以上のサイズを持つわけで、
不整合が起こるわけだな。仮にサイズが同じだったとして、何かそれでいいことがあるとも思えないし。
 
いずれにせよ、仮に動作したところで、まともに終了するとは思えない。どっかでわけのわからない潜在的なエラーとして
深刻なバグを秘めた危なげなアプリケーションが生成されるだけである。
 
正しく多態性を持つ配列を生成したいのならば、こう作るしかない。
 
DerivedClass* p[n]={new Class, new Class, new Class,…};
 
要するに、多態性を表現するために DerivedClass* 要素に対して Class インスタンスを関連付けるわけだが、
これを要素とした配列 p を考えるわけだ。各インスタンスには、配列 p の要素であるポインタ変数が対応する。当然、
 
p[0];
 
は常にポインタ変数のサイズであるため不整合が起こることもないし、*p[0]; は正しく多態性オブジェクトとして振る舞う。
 
もっとも、当然のことながら、
 
delete p;
delete [] p;
 
などとはできないし、してはならない。必ず、
 
for(int i=0;i<n;++i) delete p[i];
 
として配列要素ごとに delete で解放しなければならない。
 
では 
 
カテゴリー: コンピュータとインターネット パーマリンク

コメントを残す