お世話になります。VC++において開発を行っております。
そこ一つ疑問があります。あるクラスで以下のようなソースを書きました。
class CTest : public CDialog
{
private:
//学生構造体
struct Gakusei{
int nNum; // 出席番号
char chrName[10]; // 氏名
};
Gakusei m_Meibo; // Gakusei型のメンバ変数
private:
Gakusei GetStudent(); // m_Meiboの値を返す
・
}
このとき GetStudent()のメソッドを
Gakusei CTest::GetStudent(){
return m_Meibo;
}
と書くとコンパイルエラーになりますが、以下のように修正するとコンパイルがうまく
いきます。
CTest::Gakusei CTest::GetStudent(){
return m_Meibo;
}
ここで疑問ですがなぜこのようなときに 戻り値のクラスを明確にしないといけないの
でしょうか??ご教授よろしくお願いします。
> 戻り値のクラスを明確にしないといけないのでしょうか??
メンバ関数を定義するときに、
> CTest::GetStudent
というように、どのクラスのメンバ関数かというのを示さないといけないのと同様、
> CTest::Gakusei
CTestクラスのGakusei構造体というようにしてあげないといけないです。
クラス宣言の中での、メンバ関数宣言では、
そのクラス構造体やメンバ関数がなんなのかわかっているので、
Gakusei GetStudent();
としてもエラーにはなりません。
> Gakusei CTest::GetStudent(){
> return m_Meibo;
> }
Gakusei を解析する時にそれが CTest::Gakusei であることを
知るには、その先の CTest::GetStudent() まで先読みしなければなりませんが、
そういうのは面倒なので、できないことになっています。
逆に、こういう場合は無修飾でもOK。
void CTest::SetStudent(const Gakusei& g) {
...
}
Blueさん。dairygoodsさん。返事遅れましてすいません。
ご丁寧な解説ありがとうございます。
お二人の解答を見まして、的外れな疑問かもしれませんがさらに一つ疑問がでてきました。
①
>クラス宣言の中での、メンバ関数宣言では、
>そのクラス構造体やメンバ関数がなんなのかわかっているので、
>Gakusei GetStudent();
>としてもエラーにはなりません。
②
>Gakusei を解析する時にそれが CTest::Gakusei であることを
>知るには、その先の CTest::GetStudent() まで先読みしなければなりませんが
とありますが 例えばローカルのメソッド(下記参照)内のように Gakusei構造体 の変数を宣
言した場合にエラーにならないのはどうしてなんでしょう??
① クラス内宣言ではないのでクラス構造体と認識するのでしょうか??
② この場合は先読みされていることに当たるのでしょうか??
void CTest::InputStudent()
{
Gakusei meibo1;
...
}
長々とすいませんが、よろしくお願いします。
丸付き数字は環境依存文字(環境によっては表示できない可能性がある)ので
不特定の環境の人が閲覧できるWeb上の掲示板では試用しないほうがいいです。
> この場合は先読みされていることに当たるのでしょうか??
これに当たると思います。
先読みというか常にCTestクラスの~というのが決まったような状態になるのかと。
名前検索については ISO/IEC14882 や JIS X3014 の規格書 3.4 節で解説されていますが
10ページ以上を割いてるほど複雑です。
バグっているコンパイラが複数あるくらい厄介な話なので簡単に要約できません。
まあこの例について言うなら CTest::InputStudent( を見たあたりで
「クラス CTest のメンバ関数 InputStudent を定義してる」と判断できるので
その辺から名前検索の候補に「CTest のメンバ」が追加される、ということです。
# 語弊があるかな? CTest のメンバのほうが優先されるようになる、というべきかな?
関数開始の { の内側でも名前検索の候補に CTest のメンバは入ったまま。
関数終了の } で候補から CTest のメンバが外されます。
>> この場合は先読みされていることに当たるのでしょうか??
>これに当たると思います。
>先読みというか常にCTestクラスの~というのが決まったような状態になるのかと。
少し補足した方がよさそうと思ったので蛇足になるかもしれませんけれど書きます。
上記の話は先読みには当たらないと思います。
というか、むしろ先読みをするようなことはしないと考えた方がよいのでは?
tetrapodさんが言われているように関数開始の{と関数終了の}の間は、
関数のスコープ内ですからその関数がCTestクラスのメンバー関数であれば、
それはCTestクラス内と考えてよいと思います。
(クラスの静的でない関数であれば、直接メンバー変数を参照できるのと同じ)
早い話、コンパイラがソースファイルを解釈する時にスコープに関しては
記述されている順に解釈していると言うことなのだと思います。
最初に問題になっている部分はまだ関数のスコープに入る前ですから
その位置で見つかった識別子がCTestクラス内のものであるというのは
コンパイラにはわからないと言うのがシンプルな考え方ではないかと思います。
Blueさん。dairygoodsさん。tetrapodさん。PATIO さん。のみなさん!
本当にご解説ありがとうございました。みなさんの話を聞きまして C++では
一見普通に使っていても 実はとても奥の深いことを実感しました。
また 何かありましたらよろしくお願いします。ありがとうございました!!