
こんばんは、C++のプログラミングに関しての質問です。
現在、勉強がてら作っているゲームプログラミングで、躓いている部分があります。
現在、プレイヤーではないオブジェクトの描画を以下のソースコードで描画しています。
for(Check_OBJ=1;Check_OBJ<OBJ_num;Check_OBJ++)
OBJ_Array[Check_OBJ]->Draw_Graph(PL_Array[1]->Ref_x(),PL_Array[1]->Ref_y());
OBJ_ArrayはObjectクラス、PL_ArrayはPlayerクラス、Ref_変数名 は変数名の値を返す関数です。
このソースコードを、Objectクラスのメンバ関数Action()の中に入れたいのですが、エラーが出てしまうのです、ソースコードは以下の通りです。
void Object::Action()
{
Draw_Graph(PL_Array[1]->Ref_x(),PL_Array[1]->Ref_y());
}
エラー内容は
error C2227: '->Ref_y' : 左側がクラス、構造体、共用体、ジェネリック型へのポインターではありません。
error C2027: 認識できない型 'Player' が使われています。
です。
Playerクラスが定義されてないと認識しているのかと思い、前方宣言もしてみたのですが改善できず、どうすれば良いのか解りません。
クラス内で他のクラスへアクセスするためには何か他の処理が必要なのでしょうか・・・?
解決方法をご存知の方がいたら教えて頂けると助かります、よろしくお願いします。
No.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; }
};
下記の解答を見て、問題が解決してお礼を書き込んでいる最中にこちらの解答に気が付きました。
お察しの通りPL_Arrayはグローバルに宣言していました、セキュリティの面で問題があるようですので、後ほど見直して見たいと思います。
先程の解答を見た後、試行錯誤して、#inluce "Player.h"をアクション関数の上に置くか、アクション関数をPlayer.hの中に持ってくる、等の方法で解決することが出来ました、ありがとうございます。
その後、この解答を見てインライン関数について自分でも少し調べてみたのですが、インライン関数とは関数を呼び出すコードの中に直接定義を呼び出し実行する、ということ・・・ですよね?
ちょっとinline関数の方は見て直ぐに理解するのは出来なかったので、少々勉強してみることにします、ありがとうございます。
No.1
- 回答日時:
前回質問で私は一辺に色々と書いたので、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クラスをインクルードしていなかったことが原因のようでした。
そこを修正すると、無事にエラーが出なくなりました、有難うございます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- JavaScript EasyUIのSubGrid(jquery)におけるObjectに入れた連想配列について 1 2022/05/02 11:21
- Visual Basic(VBA) EXCEL VBAにて動的にCheckBOXを複数作成し、同BOXにイベントを追加したい 1 2023/03/16 07:05
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
- Visual Basic(VBA) エクセルのマクロについて教えてください。 2 2023/03/08 09:08
- その他(プログラミング・Web制作) pythonで変数にオブジェクトを代入するにはどうしたらよいでしょうか 2 2023/08/20 20:36
- PHP PHPでCSVを出力するさいに、ループの中で前の行の値を変更したい 3 2022/10/27 17:44
- Visual Basic(VBA) エクセルのマクロについて教えてください。 4 2023/03/02 08:40
- Visual Basic(VBA) エクセルVBAで以下のようなコードを書いたらエラーになりました。何処が間違っているの教えて? 1 2023/02/10 18:30
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
戻り値を返す関数の前に(void)...
-
既定のコンストラクタがありま...
-
C#でテンキーの操作は可能でし...
-
多重定義が起きている?--lnk20...
-
静的でないメンバ関数の呼び出...
-
リージョンのフレームを描画す...
-
関数名の名前の衝突について。
-
C++にてtemplateで受け取った任...
-
DLLの関数呼び出しで引数がある...
-
C言語 extern について
-
C言語 int main(void) main()
-
privateなnamespaceメンバ
-
関数の戻り値にその関数のポイ...
-
PowerShellにてツリービュー入...
-
Aの値からBの値を除するとは??
-
fgetsなどのときのstdinのバッ...
-
「指定されたキャストは有効で...
-
Enterキーを押されたら次の処理...
-
java初心者です。入力されたの...
-
C言語のステップ数をカウントす...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
【gcc・cygwin】multiple defin...
-
多重定義が起きている?--lnk20...
-
const_castのつかいどころを教...
-
C++にてtemplateで受け取った任...
-
既定のコンストラクタがありま...
-
戻り値を返す関数の前に(void)...
-
静的でないメンバ関数の呼び出...
-
int main()、void main()、void...
-
C# KeyDownイベントでショート...
-
C# Controls.Addで動的に配置し...
-
(void)0 はどんな意味ですか
-
gcc: incompatible pointer type
-
_beginthreadにて発生するコン...
-
C#でラジオボタンを設定に記録...
-
C#でテンキーの操作は可能でし...
-
C++別のオブジェクトからメンバ...
-
CTabCtrl:TABインデックス単位...
-
見た目は同じソースなのにエラ...
-
pictureboxの画像を削除するには?
-
【VC++6.0】イベントハンドラ関...
おすすめ情報