C++の基礎: オブジェクト配列とオブジェクトポインタ配列を学ぶ
概要
オブジェクト指向プログラミングとは、データ(オブジェクトの属性やプロパティ)やコードブロック(オブジェクトのメソッドや関数)を含むオブジェクトを統合する方法です。これらの属性やメソッドは、クラスに属する変数や関数であり、一般的には「クラスメンバ」と呼ばれています。
オブジェクト指向プログラミング(OOP)は、データを扱い、メモリ上の関数を扱うのに適した方法です。クラスやオブジェクトは、プロパティや関数を扱うのに最も適した方法です。オブジェクト指向プログラミングは、手続き型プログラミングに比べて多くの利点があり、C++プログラミング言語の最も特徴的な機能です。
C++の基礎:クラスとオブジェクトを学ぶの記事で、クラスを定義する方法と、このクラスからオブジェクトを作成する方法を説明し、例として1つのworkerオブジェクトを作成しました。
もしこれが1個でなく、複数個のworkerオブジェクトが必要な場合、どのようにしてそのクラスから複数のオブジェクトを作成し、どのようにしてオブジェクト配列を使用することができるでしょうか?
クラスとオブジェクトは、多くのオブジェクトを配列形式で定義するのに非常に簡単で便利です。そのため、プロパティに多くの変数を格納し、それぞれの属性に応じたメソッドを実行することができます。
以下は、こちらの記事で説明したHumanのクラス定義のコード例ですが、簡単におさらいしてみましょう。
class THuman
{
public:
string name;
int age, height;
};
そして、このTHumanクラスから、以下のようにシンプルなworkerオブジェクトを作成します。
THuman worker;
もし複数のworkerオブジェクトを作成するには、どのようにすれば良いでしょうか?非常に簡単な例では、以下のようにworker オブジェクトを作成します。
THuman worker1;
THuman worker2;
THuman worker3;
または、以下のように1行で記述します
THuman worker1, worker2, worker3;
オブジェクトが少数(例えば、オブジェクトが5個未満)であれば、この記述方法も有効ですが、オブジェクトの数が多い場合は、オブジェクト配列、つまりオブジェクトの配列を使用すべきです。
オブジェクト配列
配列はメモリに格納され、整数、浮動小数点数、文字列などを格納するために使用され、インデックスを使用して各メンバーにアクセスできます。同様にクラスに対する配列のオブジェクトを定義できます。
では、C++ではどのようにしてオブジェクト配列を作るのでしょうか?
オブジェクトは、配列変数として簡単に使用できます。例えば、この例のように、多数のworkerオブジェクトが必要な場合は、以下のように1000個分のworkerオブジェクトをすべてを定義できます。
THuman worker[1000];
そして以下のようにworkerの各オブジェクト[ ]の中に添え字(数値)を指定して、各メンバー変数を設定できます。
worker[0].name = "Kate";
worker[0].age = 35;
worker[0].height = 170;
worker[1].name = "Tom";
worker[1].age = 24;
worker[1].height = 168;
またこれらのworkerオブジェクトの各メンバー(name、age、height)を表示する簡単なコード例は、以下のようになります。
for(int i=0; i<1000; i++)
{
std::cout << worker[i].name << ' | ' << worker[i].age << ' | ' << worker[i].height << '\n';
}
オブジェクトのポインタ
C++では、オブジェクトはオブジェクトのポインタとして定義することができます。ポインタは、メモリブロックのアドレスを指す正の整数です。ここでは、メモリブロックがオブジェクトになります。したがって、各操作で、オブジェクトの完全なプロパティをコピーする代わりに、オブジェクトの唯一のアドレスを使用して、このオブジェクトのすべてのプロパティとメソッドにアクセスできます。C++では、ほとんどのオブジェクトはポインタとして使用され、これにより関数が高速に実行できます。 なぜなら、オブジェクトのアドレスデータを使うだけで、そのオブジェクトの完全なプロパティやメソッドにアクセスできるためです。
THuman *worker;
ポインタオブジェクトの割り当て
このオブジェクトのプロパティを設定したり、メソッドを使用したりするには、以下のようにこのオブジェクトをメモリに割り当てる必要があります。
worker = new THuman;
メモリ内の別のオブジェクトをポインタが参照している場合は、そのオブジェクトを割り当てる必要がないため、開発者は、使用するポインタの種類をよく知っている必要があります。
ポインタオブジェクトのメンバへのアクセス
ここまでの説明では、メモリ上のオブジェクトの各メンバー(worker.name、worker.ageなど)にアクセスするためにドット" . "文字を使用しました。しかしポインタオブジェクトの各クラスメンバの値を表示したい場合は、アロー" -> "演算子を使用する必要があります。
簡単に言うと、静的な配列オブジェクトには . が、ポインタオブジェクトには”->”が使用されます。オブジェクト指向プログラミングでは、ほとんどのオブジェクトがポインタオブジェクトであるため、これらのオブジェクトのメンバにアクセスするには、ほとんどの場合”->”演算子を使用します。以下はそのコード例です。
std::cout << "Name:" << worker->name << '\n';
std::cout << "Age:" << worker->age << '\n';
std::cout << "Height:" << worker->height << '\n';
オブジェクトポインタを使用した後、あるいは一般的にプログラムの最後(アプリケーションを終了するとき)には、これらのオブジェクトの割り当てをメモリから解放しなければなりません。例えば、以下のコードのようにオブジェクトをメモリから削除する必要があります。
worker->Free();
ポインタオブジェクト配列
多くのメンバーをポインタとして格納したい場合は、以下のようにポインタオブジェクトの配列を定義することができます。
THuman *worker[1000];
簡単に言えば、以下のようにすべてのメンバーをメモリに割り当てることができます。
for(int i=0; i<1000; i++)
{
worker[i] = new THuman;
}
そして、これらのポインタオブジェクトのメンバーを以下のように表示することができます。
for(int i=0; i<1000; i++)
{
std::cout << worker[i]->name << ' | ' << worker[i]->age << ' | ' << worker[i]->height << '\n';
}
そして最後に、これらのオブジェクトの使用をすべて終えたら、以下のようにメモリから解放しなければなりません。
for(int i=0; i<1000; i++)
{
worker[i]->Free();
}