こんにちは
最近 C++ を弄ってます。
ですが、C++のクラスを使おうとするとファイルのインクルードが大変で困っています orz
自分の持っている参考書とかにはインクルードについて書いてなかったのでそこら辺のことは Web で探してます;
(重複定義、循環参照とか)
今、エラーが出てしまっているのですが
色々試しても全く駄目だったので質問にきました。
error C2504: 'IObjectShot' : 定義されていない基本クラスが宣言されています。
このようなエラーが突然たくさん出てきました
多分ですがファイルのインクルードとかの問題だと思うのですが...
無暗にインクルードしまくってるせいですかね;
エラーが起こっているファイルは
Main.cpp, Board.cpp, StgFrame.cpp, PlayerShot.cpp, Enemy.cpp, EnemyManage.cpp, EnemyMove.cpp,
EnemyShot.cpp, EnemyTex.cpp
です
エラーが出てしまっているプロジェクトファイルとソースファイルを添付しました
かなり初歩的なミスだと思いますが、どうかご教授お願いします m(_ _)m
ソースコードが大変なことになっているのでいつか書き直します;
とても見難いです。すみません orz
処理も訳のわからないことをしているかもしれません...(命名規則皆無ですし)
VC++2008EE , DXライブラリ
C++ 定義されていない基本クラス
Re:C++ 定義されていない基本クラス
原因までは分からなかったのですが、恐らく「source\EnemyShot.h」をどこかのincludeで循環参照してクラス情報を読み込んでいます。
そのため継承のために定義が必要な「IObjectShot」クラスがincludeされていないためエラーが出ているようです。
ここまで複雑だとちょっと読み解く自信がないので、自分が使ってる手法を記載してみます。
僕もちゃんとしたクラス定義の参考書で学習したわけではないので間違った事を書くかもしれません、ご了承下さい。
1.相互参照を行うクラス構成は継承単位で1ヘッダにまとめる
継承順に矛盾が無いように継承されるクラスから読み込んでおく
#include "GameObject.h"
#include "Enemy.h"
...
#include "IObjectShot.h"
#include "EnemyShot.h"
#include "PlayerShot.h"
...
2.各クラスで1で作成したヘッダファイルをincludeする
1で作るものは継承単位で分けても良いですし、少々無駄にincludeしても良いなら一つのヘッダにすべて記述して書いても良いと思います。
あらかじめ、必要なクラス情報が定義されたヘッダを読み込むので定義の循環参照は起きません。
3.メンバ変数・引数・戻り値等にクラスポインタを使用し、使用するクラスは「class XXX」定義
タイトル通りですが、変数や引数は全てポインタにしておいて、クラス宣言前にclassでそれぞれ定義しておくと
2で必ず実体定義があるはずなのでコンパイル時には問題ありません。
1,2,3の手順だと必ず無駄にincludeする定義が出来てしまいますが、ゲーム等では複雑な相互参照が起こりやすいため、クラスの仕組みを変えたり新しい相互参照が出来るたびにinclude順を手直しする手間に比べたら大分楽だと思います。
また、この手順を使用するとcpp1個のコンパイルコストもがんがん上がってしまうので、プリコンパイル済みヘッダーを使用するとリビルドしてもすぐ終わると思います。
そのため継承のために定義が必要な「IObjectShot」クラスがincludeされていないためエラーが出ているようです。
ここまで複雑だとちょっと読み解く自信がないので、自分が使ってる手法を記載してみます。
僕もちゃんとしたクラス定義の参考書で学習したわけではないので間違った事を書くかもしれません、ご了承下さい。
1.相互参照を行うクラス構成は継承単位で1ヘッダにまとめる
継承順に矛盾が無いように継承されるクラスから読み込んでおく
#include "GameObject.h"
#include "Enemy.h"
...
#include "IObjectShot.h"
#include "EnemyShot.h"
#include "PlayerShot.h"
...
2.各クラスで1で作成したヘッダファイルをincludeする
1で作るものは継承単位で分けても良いですし、少々無駄にincludeしても良いなら一つのヘッダにすべて記述して書いても良いと思います。
あらかじめ、必要なクラス情報が定義されたヘッダを読み込むので定義の循環参照は起きません。
3.メンバ変数・引数・戻り値等にクラスポインタを使用し、使用するクラスは「class XXX」定義
タイトル通りですが、変数や引数は全てポインタにしておいて、クラス宣言前にclassでそれぞれ定義しておくと
2で必ず実体定義があるはずなのでコンパイル時には問題ありません。
1,2,3の手順だと必ず無駄にincludeする定義が出来てしまいますが、ゲーム等では複雑な相互参照が起こりやすいため、クラスの仕組みを変えたり新しい相互参照が出来るたびにinclude順を手直しする手間に比べたら大分楽だと思います。
また、この手順を使用するとcpp1個のコンパイルコストもがんがん上がってしまうので、プリコンパイル済みヘッダーを使用するとリビルドしてもすぐ終わると思います。
Re:C++ 定義されていない基本クラス
基底クラスとして使われているIObjectShotクラスを定義しているヘッダをインクルードしていないのが問題です。
エラーが発生するヘッダの全てに、#include "ObjectShot.h"を書き加えればエラーは消えると思います。
基本的に、ヘッダ内で他のヘッドをインクルードするべきではありません。
なるべくソースファイル内でインクルードしてください。
エラーが発生するヘッダの全てに、#include "ObjectShot.h"を書き加えればエラーは消えると思います。
基本的に、ヘッダ内で他のヘッドをインクルードするべきではありません。
なるべくソースファイル内でインクルードしてください。
Re:C++ 定義されていない基本クラス
>無暗にインクルードしまくってるせいですかね
まぁそうですね、しまくっているというか、各ファイルに必要なインクルードの区別がついておらず
闇雲にインクルードしているようにみえます。
少し整理が必要ですね。
>ソースコードが大変なことになっているのでいつか書き直します;
いつか、と言わずいい機会ですので今見直してみてはいかかでしょうか。
綴りミスとか、予約済み識別子の使用とか、潜在的バグとかが見つかるかもしれませんし。
Re:C++ 定義されていない基本クラス
返信ありがとうございます m(_ _)m
>>ねこ様
わざわざ詳しく教えて頂き、ありがとうございます
その方法だったら一つのヘッダファイルを変更するだけでいいんですね。非常に参考になりました
今度、その方法で書き直してみます。(実体を持ってしまっているクラスがあるので変更が大変そうです;
後、プリコンパイル済みヘッダーというものがあったんですね・・・
こちらもかなり参考になりました。本当にありがとうございます
>>MNS様
>エラーが発生するヘッダの全てに、#include "ObjectShot.h"を書き加えればエラーは消えると思います。
全てのヘッダファイルに書いてみたんですが消えませんでした;
>ヘッダ内で他のヘッドをインクルードするべきではありません。
参考にしていたソースコードがヘッダファイルでインクルードしていたので
てっきりヘッダファイルでインクルードしないといけないのかと思っていました;
今度から変えようと思います。ありがとうございます。
>>ねこ様
わざわざ詳しく教えて頂き、ありがとうございます
その方法だったら一つのヘッダファイルを変更するだけでいいんですね。非常に参考になりました
今度、その方法で書き直してみます。(実体を持ってしまっているクラスがあるので変更が大変そうです;
後、プリコンパイル済みヘッダーというものがあったんですね・・・
こちらもかなり参考になりました。本当にありがとうございます
>>MNS様
>エラーが発生するヘッダの全てに、#include "ObjectShot.h"を書き加えればエラーは消えると思います。
全てのヘッダファイルに書いてみたんですが消えませんでした;
>ヘッダ内で他のヘッドをインクルードするべきではありません。
参考にしていたソースコードがヘッダファイルでインクルードしていたので
てっきりヘッダファイルでインクルードしないといけないのかと思っていました;
今度から変えようと思います。ありがとうございます。
Re:C++ 定義されていない基本クラス
返信ありがとうございます m(_ _)m
>>Justy様
>闇雲にインクルードしているようにみえます。 少し整理が必要ですね。
StgFrame がシューティングゲームを管理しているんですが
敵が自機の位置を知るためにStgFrameをインクルードすると(StgFrame内にプレイヤーのポインタがあるので)
ほとんどのヘッダがインクルードされてしまっています;
構造上問題がありそうですね・・・
正直あまりヘッダ、及びインクルードについて理解できていません;
>いつか、と言わずいい機会ですので今見直してみてはいかかでしょうか。
そうですね、確かに良い機会ですので今一度見直した方がいいですね。
ご助言ありがとうございます m(_ _)m
>>Justy様
>闇雲にインクルードしているようにみえます。 少し整理が必要ですね。
StgFrame がシューティングゲームを管理しているんですが
敵が自機の位置を知るためにStgFrameをインクルードすると(StgFrame内にプレイヤーのポインタがあるので)
ほとんどのヘッダがインクルードされてしまっています;
構造上問題がありそうですね・・・
正直あまりヘッダ、及びインクルードについて理解できていません;
>いつか、と言わずいい機会ですので今見直してみてはいかかでしょうか。
そうですね、確かに良い機会ですので今一度見直した方がいいですね。
ご助言ありがとうございます m(_ _)m
Re:C++ 定義されていない基本クラス
そうですね。確かに全てのファイルでインクルードしてもエラーが消えませんね。
「定義されていない基本クラスが宣言されています。」
というエラーは、基底クラスの定義の前に派生クラスが定義されているため発生するエラーです。
例えば、
このとき、もし最初にA.hがインクルードされたとしても、
Aクラスを定義する前にC.hをインクルードしてしまい、
また、C.hがB.hをインクルードするため、
結果的にBクラスの定義がAクラスの前に行われてしまうのです。
yuさんのコードのエラーはこれが原因ですが、
今のプログラムコードは非常にわかりにくいものと成っています。
ですから、一旦全てのヘッダのインクルードを消してみましょう。
そして、インクルードするファイルを整理しましょう。
ヘッダ内でインクルードするファイルは、
そのヘッダで定義するクラスで利用しているクラスを定義しているヘッダのみにしましょう。
クラスがポインタの場合には、インクルードする必要はありません。
それ以外は、全てソースファイルでインクルードするようにしましょう。
そうすることによって、各ヘッダ同士の関係がわかりやすくなるだけではなく、
コンパイル時間を大幅に短縮することが出来ます。
「定義されていない基本クラスが宣言されています。」
というエラーは、基底クラスの定義の前に派生クラスが定義されているため発生するエラーです。
例えば、
<---A.h---> #include "C.h" class A { //... }; <---B.h---> #include "A.h" class B :public A { //... }; <---C.h---> #include "B.h"このようなコードがあるとしましょう。
このとき、もし最初にA.hがインクルードされたとしても、
Aクラスを定義する前にC.hをインクルードしてしまい、
また、C.hがB.hをインクルードするため、
結果的にBクラスの定義がAクラスの前に行われてしまうのです。
yuさんのコードのエラーはこれが原因ですが、
今のプログラムコードは非常にわかりにくいものと成っています。
ですから、一旦全てのヘッダのインクルードを消してみましょう。
そして、インクルードするファイルを整理しましょう。
ヘッダ内でインクルードするファイルは、
そのヘッダで定義するクラスで利用しているクラスを定義しているヘッダのみにしましょう。
クラスがポインタの場合には、インクルードする必要はありません。
それ以外は、全てソースファイルでインクルードするようにしましょう。
そうすることによって、各ヘッダ同士の関係がわかりやすくなるだけではなく、
コンパイル時間を大幅に短縮することが出来ます。
Re:C++ 定義されていない基本クラス
返信ありがとうございます m(_ _)m
>>MNS様
なるほど・・・よく理解できました
ありがとうございます。非常に参考になります
おかげさまでエラーが消えました。
エラーが消えたことより、皆様からコメントで学べたことが非常にうれしいです
本当にありがとうございました m(_ _)m
>>MNS様
なるほど・・・よく理解できました
ありがとうございます。非常に参考になります
おかげさまでエラーが消えました。
エラーが消えたことより、皆様からコメントで学べたことが非常にうれしいです
本当にありがとうございました m(_ _)m