- ベストアンサー
クラス内で他のクラスへアクセスする方法は?
- C++のプログラムで、クラス内で別のクラスへアクセスする方法について質問があります。
- 現在、ゲームプログラミングの中でオブジェクトの描画を行っているのですが、エラーが発生してしまいます。
- 特に、Objectクラスのメンバ関数Action()内でPlayerクラスへアクセスする際にエラーが出ています。解決方法を教えてください。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
>Objectクラスのメンバである必要があります。 あ、一応PL_Arrayがもしグローバルだったらそうでなくても出来ますねw (よほどいろんな場所から使われたりするとか、特別な事情がない限りお勧めはできませんが) ※以下はC++の仕様についての補足説明です。 なお、「宣言」と「定義」というのは言葉の上では事実上曖昧になる場合もありますし、同時に行われる場合もありますが、基本的には別々と考えてください。 クラスの場合、(前方)宣言というのはあくまで class A; Aの内容は知らないけどAというものがある ということしか示しません。 Aのメンバを使いたかったら class A { public: void f(); }; こういう風に書かれたものが、使いたい場所より前に書いてないといけません。 通常 #include によって、前に書かれたのと同じことにしているわけです。 で、さらに言うとこのときの void f(); は「宣言」です。 これは、引数なしで戻り値なしのfという関数をAはメンバとして持ってる。 という事を示していますが (ホントはconstじゃないthiscallのメンバ関数、とか、これだけでももうちょい色々情報があるのですが) 少なくとも関数の定義(実装)の事はこの部分だけでは全く分かりません。 全く分からなくても、これだけの情報があればfという関数を呼び出すには十分なのです。 もちろん、宣言だけして どこにも実装(関数定義)を書かなければ コンパイルは通るものの「リンクエラー」が発生してビルドできません。 なので、どこかに書いてやる必要はあります。 ただし、複数書いてもやはりいけません。 全く同じ関数の「定義部分」を複数書くと、どっちの定義を使えばいいかコンパイラが判断できなくなりますから 関数定義を書けるのは一か所だけです。 どこに書くかは class A { public: void f(); }; が見える位置で、他の場所に何度もインクルードされない、どっかのソースに書く、というのが一般的になります。(ヘッダに書いたりすると何度もインクルードされて、「何度も書いた」事と同じになってしまう可能性がある。) ただし class A { public: inline void f(); }; などとした場合(やtemplateにした場合など)は インライン化するためには関数の定義が見えないといけません。 (実際にインライン展開されるかどうかは別として) なので、この場合 f関数を使用する前には f関数の内容が見えてないといけません。 ただしインライン関数の場合は ヘッダに書いて何度も別のところでそのヘッダをインクルードしても 大丈夫ということになっています。 なので class A { public: inline void f(); }; inline void A::f(){} こういう風にヘッダに書いておくことが可能です。 もっというと class A { public: inline void f(){} }; このように宣言と定義を同時に書くこともできます。 さらに言えば class A { public: void f(){} }; class や struct内では、このようにinlineを書かずに 関数の宣言と定義を同時に行う事もできます。 この場合inlineが書かれていませんが 「書かれているのと同じ意味」として扱われます。 巨大な関数で、かついろんな場所から呼び出される場合はやらない方がいい可能性が高いですが ささいなSetterやGetterではこのようにするのが大抵良いです。 class A { int num; public: void SetNum(int i){ num = i; } int GetNum() const { return num; } };
その他の回答 (1)
- LongSecret
- ベストアンサー率68% (22/32)
前回質問で私は一辺に色々と書いたので、C++に触れ初めて間もない状態では、一発で隅々まで吸収するのはさすがに難しいと思いますので 確認していきましょう。 void Object::Action() { Draw_Graph(PL_Array[1]->Ref_x(),PL_Array[1]->Ref_y()); } まず、この書き方だと PL_ArrayはPlayerクラスのポインタのポインタ あるいはポインタの配列になっていて、同時にObjectクラスのメンバである必要があります。 なのでObjectクラスのヘッダ(宣言)部分で、まず、こういった形になっていますか? class Player; class Object { Player** PL_Array; //あるいはPlayer* PL_Array[定数]; 戻り値 Draw_Graph(引数のリスト); public: void Action(); }; つぎに #include "Playerクラスの内容が書いてあるヘッダ名.h" void Object::Action() { Draw_Graph(PL_Array[1]->Ref_x(),PL_Array[1]->Ref_y()); } というように Action関数の上にヘッダのインクルードの記述がありますか? (これ以外の事は通常では考えにくいので、これらの両方を満たしていてなおかつこうなるという場合は、ヘッダとソースのコードを正確に載せてみてください。)
お礼
解答ありがとうございます。 教えて頂いた2つの点についてソースコードを確認し、修正してみたところ、Action()の上にPlayerクラスをインクルードしていなかったことが原因のようでした。 そこを修正すると、無事にエラーが出なくなりました、有難うございます。
お礼
下記の解答を見て、問題が解決してお礼を書き込んでいる最中にこちらの解答に気が付きました。 お察しの通りPL_Arrayはグローバルに宣言していました、セキュリティの面で問題があるようですので、後ほど見直して見たいと思います。 先程の解答を見た後、試行錯誤して、#inluce "Player.h"をアクション関数の上に置くか、アクション関数をPlayer.hの中に持ってくる、等の方法で解決することが出来ました、ありがとうございます。 その後、この解答を見てインライン関数について自分でも少し調べてみたのですが、インライン関数とは関数を呼び出すコードの中に直接定義を呼び出し実行する、ということ・・・ですよね? ちょっとinline関数の方は見て直ぐに理解するのは出来なかったので、少々勉強してみることにします、ありがとうございます。