第2章 メンバ

 今回は、前回のプログラムの文法的な意味について話します。さぁ、あなたの推理は当たっているでしょうか?


 さて、今回の要点...はちょっと最後に回します。推理小説を読んでる途中に犯人を言われるようなものですからね。

 では、いってみましょう。


 先ずは、クラスの宣言の中に関数のプロトタイプが書いてありました。

void Disp();

 メンバ関数を使うには、先ずクラス宣言の中にその関数のプロトタイプを書きます。これは単純な話ですね。

 次には、今までにはちょっと見たことのない関数の定義がありました。

void SStudent::Disp()
{
    cout << "名前 : "   << szName    << endl
         << " 国語 : " << nJapanese << " 点, "
            "数学 : "   << nMath     << " 点, "
            "英語 : "   << nEnglish  << " 点" << endl;
}

 ここではメンバ関数の中身を定義しているのだということは簡単に分かると思います。メンバ関数の中身を定義することを「実装する」と言います。ここでは「クラス SStudent のメンバ関数 Disp を実装している」となります。

 メンバ関数を実装するときは、関数名の前に <クラス名>:: をつけます。どのクラスの Disp なのかを表しているわけですね。この :: は演算子ではありませんが、スコープ解決演算子と同じと考えて問題ありません。


 さて、ここまでは何の問題もありません。問題は szName などを素のまま使っているというところです。この szName は何の szName なのでしょうか?

 これは、このメンバ関数を呼んだ時に使ったオブジェクトの szName なのです。つまり、どのメンバ関数を呼んだかによって、szName がどの szName なのかが変わってしまうのです。

 メンバ関数を呼んでいると思われるのは

for(i = 0; i < ELEM(students); i++)
    students[i].Disp();

の部分です。

 先ず i が0のときは、students[0].Disp(); が実行されます。つまり、この時 Disp の中の szName は student[0] の szName になります。nJapanese なども同様です。

 次に i が1になると、students[1].Disp(); が実行されます。つまり、この時 Disp の中の szName は student[1] の szName になります。同じ szName でも、どのオブジェクトを使って呼んだかによってモノが変わってしまうのです。

 また、メンバ関数を呼ぶときには、メンバ変数と同じようにピリオド (.) を使って呼ぶことができます。もちろんポインタを使うときは -> を使います(「そうだっけ?」という人は第1部第60章を読み返しましょう)。


 このことが考えにくい人は、構造体の時と同じように考えればいいでしょう。

void Disp(const SStudent& student)
{
    cout << "名前 : "   << student.szName    << endl
         << " 国語 : " << student.nJapanese << " 点, "
            "数学 : "   << student.nMath     << " 点, "
            "英語 : "   << student.nEnglish  << " 点" << endl;
}

の szName は関数に渡されたオブジェクトの szName ですね。メンバ関数でも内部的にはこれと同じことをしています。つまり、メンバ関数を呼ぶときにオブジェクトのアドレスを渡し、メンバ関数ではそのアドレスを使って szName を利用しているのです。

 たまにしか2つ以上の実体を作らないようなクラスを使っていると、次のように誤解することがあります。

SStudent studentAkai = { "赤井孝", 73, 98, 86, };

void Func()
{
    SStudent student;
    student.Disp();  // ←これが問題のコード
}

 初めに studentAkai というオブジェクトを作っています。普通、このオブジェクトしか作らないとします。

 すると、初めの内は Func 関数でやっているようなことをしてしまうかもしれません。この Disp は studentAkai を初期化したときの値を表示してくれると期待してしまうのです。

 しかし、studentAkai と student は全く別のオブジェクトなので、Disp で studentAkai の内容が表示されることは(偶然を除いては)ないのです。

 この「クラス」は「構造体」と同じように「型」です。クラスの宣言を行った時点では、メモリ上のどこにも実体は存在しません。そして、沢山インスタンスを作ってもそれぞれは全く別のものです。このことは、常に頭に入れておくようにしましょう。


 では、今回の要点です。


 それでは、次回まで。


第1章 とにかく作ってみよう | 第3章 コンストラクタ

Last update was done on 2000.8.5

この講座の著作権はロベールが保有しています