• ベストアンサー

ソースの分け方がよく分かりません

ソースの量が増えてきたので分けることにしました。 ・メインのソース ・クラスの定義のヘッダ(1),(2) ・クラスのメンバ関数の定義用のソース(1)、(2) このように3種類の構成にしています。 そして、クラス(1)の実体は次のように配列の形で作ります。 int aaa[] = {1,2,3}; const int Num = (sizeof aaa /sizeof aaa[0]); static DATA data[Num]; しかし、上記のコードをどこに書けば良いか分からず、とりあえずクラス(1)のソース内に書いたんですが、クラス(2)のヘッダとソース内でもNumを使うため、このままではNumが定義されていないというエラーになります。一体どのように書くべきでしょうか。よろしくお願いいたします。

  • sanato
  • お礼率72% (170/236)

質問者が選んだベストアンサー

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.5

あっ直し忘れました。 Enemy.hはこれが正解です。 /*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, } State; private: Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; public: void Initalize(Math::Vector3D EnemyPos); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); };

sanato
質問者

お礼

何度もありがとうございます。 いろいろ書き直して何とかEnemyNumをメインのソースのみに収めることができました。 おかげさまで素晴らしい学習ができました。これからに生かしていこうと思います。

その他の回答 (4)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.4

ソースを見て理解しました。クラスとしての設計が間違っています。 クラスの構造を見ると手続き言語の組み方でクラスを書いていますね。 1つのクラスは1体に敵データを保持して、一体のデータだけを処理する形に組みなおす必要があります。 こんな感じ↓。初期化までしか書いてないです。 void dummymain(void) { // 将来的には、データファイル移すべきですよ。 Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); // インスタンスはメインが保持するだけでよい。 // 本当はnewで動的にインスタンス生成すること。EnemyNumがマップごとに可変するのはゲームでは当たり前なので。 // そもそもENEMY_DATAクラスはEnemyNumを知る必要はありませんよ。 // メインが知っていれば済むことです。 ENEMY_DATA Enemy[EnemyNum]; // 初期化 //Initalizeでは無くコンストラクタでやるべきだと思いますけど取り合えずと言うことで。 for(int i=0;i< EnemyNum;i++) { Enemy.Initalize(EnemyPos[i]); } } /*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, } State; private: Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; public: void Initalize(); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); }; /*ここからEnemy.cpp*/ #include"Enemy.h" void ENEMY_DATA::Initalize(Math::Vector3D EnemyPos) { State = STATE_STANDBY; pActor = NULL; vStartPos = EnemyPos; } void ENEMY_DATA::Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel) { if( State == STATE_STANDBY ) { State = STATE_ACTIVE; pActor = pScene->CreateActor( pModel ); } } void ENEMY_DATA::Update(Sint32 Time) { switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: vPosition.Set(vStartPos.x + Math::Sin( Time * 256 ) * 20.0f,vStartPos.y,vStartPos.z ); pActor->TransformReset(); pActor->Translation(vPosition); pActor->TransformUpdate(); break; } } void ENEMY_DATA::Rendering( void ) { switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: pActor->TransformReset(); pActor->Translation( vPosition ); pActor->Scaling(0.5f,0.5f,0.5f ); pActor->TransformUpdate(); pActor->RenderingRequest(); break; } }

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

mainのヘッダを作れば解決する気もするが。 ただし、実体は1つにしてextern宣言する必要あり。 int aaa[] = {1,2,3};これもextern const int Num = (sizeof aaa /sizeof aaa[0]);これもextern static DATA data[Num]; これがヘッダにあるとまずい。つうかDATAってクラス名? と書いといてなんだが、これってクラスの設計そのものが変な気がする。 クラスの定義部分だけでも見たいのでお願いします。

sanato
質問者

補足

/*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, }State; Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; void Initalize(); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); }; /*ここからEnemy.cpp*/ #include"Enemy.h" Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); ENEMY_DATA Enemy[EnemyNum]; void ENEMY_DATA::Initalize() { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; EnemyObj.State = STATE_STANDBY; EnemyObj.pActor = NULL; EnemyObj.vStartPos = EnemyPos[i]; } } void ENEMY_DATA::Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; if ( EnemyObj.State == STATE_STANDBY ) { EnemyObj.State = STATE_ACTIVE; EnemyObj.pActor = pScene->CreateActor( pModel); } } } void ENEMY_DATA::Update(Sint32 Time) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: EnemyObj.vPosition.Set(vStartPos.x + Math::Sin( Time * 256 ) * 20.0f,vStartPos.y,vStartPos.z ); EnemyObj.pActor->TransformReset(); EnemyObj.pActor->Translation(vPosition); EnemyObj.pActor->TransformUpdate(); break; } } } void ENEMY_DATA::Rendering( void ) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: EnemyObj.pActor->TransformReset(); EnemyObj.pActor->Translation( vPosition ); EnemyObj.pActor->Scaling(0.5f,0.5f,0.5f ); EnemyObj.pActor->TransformUpdate(); EnemyObj.pActor->RenderingRequest(); break; } } } 質問内容に書いたものを正確に示すと以下のようになります。 Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); static ENEMY_DATA Enemy[EnemyNum]; Enmeyの位置を書き足す分だけ生産しようという仕組みです。質問内容で言うところのクラス(1)です。

  • BLK314
  • ベストアンサー率55% (84/152)
回答No.2

>とりあえずクラス(1)のソース内に書いたんですが、クラス(2)のヘッダとソース内>でもNumを使うため、このままではNumが定義されていないという >エラーになります。 Numの情報が共有されるのでNumの定義をクラス(1)のヘッダに記述し、 クラス(2)のヘッダで"includeする必要があります。 しかし、この場合 Numがaaaを使って定義されています。 そのaaaは int aaa[] = {1,2,3}; と定義されています。 クラス宣言ではこの記述はできません。 恐らく、この様に記述すれば int aaa[] = {1,2,3,4} とするだけで 自動的にNumが4となり、 その情報をクラス(2)でも使いたいのだと思います。 この様な記述はできません。 ソースを分割するのは良いことですが、 >ソースの量が増えてきたので分けることにしました。 安易に分けようとするのも良くないことです。 分割する際には、 それぞれのクラスが果たすべき役割を明確にして、 分割することが必要です。 また、それぞれの情報をできるだけブラックボックス化できるよう 考えるべきです たとえば、 クラス(1)は1レコードを表す クラス(2)はクラス(1)の集合を表す という風に分けます クラス(1)はそれがどのように使われるか一切関知すべきではありません。 クラス(2)はクラス(1)がどのようなフィールドからなるか知らなくても動作するべきです。(現実には厳しい場合もあります。それでも、知らなければならない情報が少ない方が好ましいです。) もう一度、クラス分けを考え直すことをお勧めします、

sanato
質問者

お礼

多くなったらとりあえず分ければ良いという考えを持っていましたが、後先考えずに分けてはいけないのですね。 今からもう一度見直してきます。ありがとうございました。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

>・クラスの定義のヘッダ(1),(2) >・クラスのメンバ関数の定義用のソース(1)、(2) このあたりを見せていただいてもいいですか?

sanato
質問者

補足

/*ここからSystem.h*/ #include "../../../../Selene.h" using namespace Selene; class SYSTEM { public: Bool LockOnStart; Float Distance[EnemyNum]; Float MostShortDistance; Math::Vector3D LockOnPos; Bool LockOn; Sint32 TargetID,Min; SYSTEM() { LockOnStart = false; LockOn = false; } enum LOCK_ON_STATE { STANDBY, START, ACTIVE, }LockOnState; void LockOn_Initalize(); void LockOnManage(Math::Vector3D vPlayerPos,Renderer::IRender *pRender); void DebugPrint(Renderer::IRender *pRender); void MeasureDistance(Math::Vector3D vPlayerPos,Renderer::IRender *pRender); void MeasureMostShortDistance(Renderer::IRender *pRender); void SetLockOnEnemy(); void PutLockOn(); }System; /*ここからSystem.cpp*/ #include"System.h" void SYSTEM::LockOn_Initalize() { LockOnState = STANDBY; } void SYSTEM::LockOnManage(Math::Vector3D vPlayerPos,Renderer::IRender *pRender) { if(LockOnState == STANDBY) { MeasureDistance(vPlayerPos,pRender); MeasureMostShortDistance(pRender); if(LockOn)LockOnState = START; } if(LockOnState == START)SetLockOnEnemy(); if(LockOnState == ACTIVE) { PutLockOn(); MeasureDistance(vPlayerPos,pRender); } } void SYSTEM::DebugPrint(Renderer::IRender *pRender) { } void SYSTEM::MeasureDistance(Math::Vector3D vPlayerPos,Renderer::IRender *pRender) { for(int i=0;i<EnemyNum;i++) { Float Ax,Ay,Az,Bx,By,Bz; Ax = vPlayerPos.x; Ay = vPlayerPos.y; Az = vPlayerPos.z; Bx = Enemy[i].vPosition.x; By = Enemy[i].vPosition.y; Bz = Enemy[i].vPosition.z; Distance[i] = fabs(sqrt((Ax-Bx)*(Ax-Bx) + (Ay-By)*(Ay-By) + (Az-Bz)*(Az-Bz))); } } void SYSTEM::MeasureMostShortDistance(Renderer::IRender *pRender) { static int j = 0; for(int i=0;i< EnemyNum;i++) { if(MostShortDistance >= Distance[i] ) { MostShortDistance = Distance[i]; Min = i; } else if(MostShortDistance == Distance[0]) { MostShortDistance = Distance[0]; Min = 0; } } pRender->DebugPrint( Math::Point2DI(85,460), CColor(255,255,255), "jは:%d",j); } void SYSTEM::SetLockOnEnemy() { TargetID = Min; LockOnState = ACTIVE; } void SYSTEM::PutLockOn() { if(Distance[TargetID] > 50.0f || LockOn == false) { LockOnState = STANDBY; LockOn = false; }; LockOnPos = Enemy[TargetID].vPosition; } これが質問内容で言うところのクラス(2)です。 生産したEnemyの位置を把握し、Enemyの各々の位置と自身との距離など測定しようとするものです。

関連するQ&A

  • 文字列のメンバ変数を外部変数のように扱いたい

    済みません。質問なのですが、 メンバ変数を外部変数のように扱うにはどうしたらよいのでしょうか? int型などの場合、 class test{ static const int a; }; const int test::a = 10; とすればよいですよね? これをcharの配列にして class test{ static char a[7][32]; }; char test::a[0] = "test"; とすると サイズが0の配列を割り当てまたは宣言しようとしました というコンパイルエラーがでてしまいます…。 多次元配列の場合はstatic変数としてもてないのでしょうか? char** として宣言してもどこでnewを行えばよいか解りません。 コンストラクタの中で行えば そこでstaticではなくなってしまいますし…。 後、できればstringクラスの配列で持ちたいのですが #include <string> class test{ static string test[7]; }; string test::test[0] = "aaa"; なんてことができますでしょうか? 質問内容が解りにくいかも知れませんが どうか教えてください。 宜しくお願いいたします。

  • オペレータ定義について

    すみません、オペレータ定義について教えてください。 ■以下のようなクラスに、[] が定義されていて、 class String { public:       ・       ・ (メンバ関数がいくつかあり)       ・       // num 番目の文字を返す       char operator[](int num) const;       char& operator[](int num); private:       char* string; }; ■関数はこのように書かれていて、 char String::operator[](int num) const {     // 文字列の num 番目の文字を返す 1     return string[num]; } char& String::operator[](int num) {      // 文字列の num 番目の文字を返す 2      return string[num]; } ■これを →[] main() から使うにはどのようにしたらいいのでしょうか?

  • static constメンバ変数(配列)の初期化について

    C++初心者です。 constメンバ変数の初期化について教えてください。 クラスの中に、static constメンバ変数(配列)を持ちたいのですが、 <コード1> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2] = {1, 2}; }; とすると、VC++ 2005では、 error C2059: 構文エラー : '{' error C2334: '{' の前に予期しないトークンがありました。関数の本体は無視されます というエラーが発生します。 何がいけないのでしょうか? また、下の様にするとOKでした。 <コード2> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2]; }; const int hoge::fuga[2] = {1,2}; こうすればコンパイルが通る事は分かったのですが、なぜこんな面倒な事をしないといけないのかが分かりません。 コード1では何がいけないのでしょうか? 以上、よろしくお願いします。

  • C言語のコンパイルエラー

    次のようなコードで (宣言等は省略します) extern int main( int argc, char *argv[]) { short ret ; ret = aaa(); } static short aaa() { /* aaa()関数の処理 */ XXXXXXXXX return 1; } というようなコードをコンパイルすると ワーニングで warning: 'aaa' was declared implicitly `extern' and later `static' warning: previous declaration of `aaa' warning: type mismatch with previous implicit declaration というようなメッセージが出ます。 これは、他のソースをまねて作ってるのですが、 参考にしたコードもこのような宣言の仕方になっているのにエラーはでまでん。 何か他にもaaaという関数の定義をしなくてはいけないのでしょうか? どうもstatic宣言とexternのところがよくわかりません。 宜しくお願いします。

  • qsortの引数について

    以下のプログラムがあります。 int compare( const char **name1, const char **name2 ) { return strcmp( *name1, *name2 ); } int main( void ) { char *names[] = { "rand", "calloc", "malloc" }; int num = sizeof names / sizeof names[0]; qsort( names, num, sizeof( names[0] ), (int (*)(const void *, const void * ))compare ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~この部分 return 0; } 上の「~~~」の上の部分のqsort関数の第4引数のキャストの意味が 分かりません。なぜ関数の前に引数が書かれるのでしょうか? またintの後にある(*)は「int型のポインタ」と言う意味なのか、 compare関数のポインタなのかも分かりません。 ご回答よろしくおねがいします。

  • VC++2005であるヘッダファイルを複数のソースから読み込みたいのですが…

    毎度お世話になっています。 現在VC++2005でUSBカメラ画像の処理プログラムを作成しているのですが、 現在こちらのEWCLIBというライブラリを利用しています。 http://www.geocities.jp/in_subaru/ewclib/ このライブラリを 一つのソースファイルからから呼び出した場合問題無いのですが、 複数のソースファイルから呼び出した場合error LINK2005 既に~で定義されています… といったエラーが出てしまいます。 複数のソースファイルからこのライブラリを利用したい場合どのようにすればいいでしょうか? このライブラリは #define EWC_BRIGHTNESS 0 … int ewc_init=0; … int ewc_ncam; … int EWC_GetImage(int num, void *buffer){ … } と単一のヘッダファイルに変数や関数の定義を行っているのですが、 複数のソースファイルからこのライブラリを利用したい場合、やはりヘッダとソースに分割する必要があるのでしょうか? 参考になるページや解決方法等、お伺いしたいです。

  • コンパイル時の静的チェックについて

    次のような配列があります。 static const int ary[]={1,2,3,4,5}; この配列の要素数が5であることは、次の方法でコンパイル時にチェック出来ます。 #define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) static_assert(ARRAYSIZE(ary) == 5); では、この配列で4以上の要素数が2であることをコンパイル時にチェックするにはどうしますか? 実行時であれば次のように出来ます。 assert(count_if(ary, ary+sizeof(ary), [](int i)->bool {return (i >= 4); }) == 2); 結果はコンパイル時に確定しているはずなのですが、この方法だとライブラリ関数を使用するので実行時にしかチェック出来ません。 「テスト用プロジェクトを作って...」というのも「コンパイル時に確認」ではないので無しとします。

  • UNIXのC++で共通クラスを作ってみんなで使いたい。

    Linux上で稼動するあるC++のプログラムを作るのに、 みんなで使えるような、共通クラスを作りたいと思っています。 クラス自体の作り方(プログラムコード)はだいたい分かるのですが、 それをどのような形(lib?またはアーカイブ?またはdll?)で 配布すると、みんなが使いやすいものになるのかが分かりません。 手順など、どなたか教えてください。 私が何とか予想できる手順を以下に書きます。 (1)普通にクラスを作成する。(例えばaaa.cppと言う名前のファイルに)   public class AAA{ public: void init(); void clean(); private: int elems; } void AAA::init(){ elems = 0; } void AAA::clean(){ elems = 0; } ※この時点でクラスの定義部分だけをヘッダーファイルとして   別ファイルにしておいた方が良いのでしょうか? (2)このクラスをコンパイルして、みんなに提供できる何らかの形にする。  ※ここがよく分かりません!!  ※”.a”というアーカイブを作成する方法は知っています。   これを作れば良いのでしょうか? (3)出来上がった共通クラスをどうにかして、他の人のプログラムで使えるようにする。  ※予想としては、(1)で作ったクラス定義のヘッダーファイルを   includeする(のかな?)   それから、コンパイルする時にmakefileの中で(2)で作った   ライブラリ(?)を一緒にリンクする(のかな?)  ※プログラム中では、いきなり    AAA testBuf = new AAA(); testBuf.init(); などと使えるのでしょうか?

  • C++のクラス内での2次元配列

    C++学習者です。Windows 10上で、Visual Studio Community 2015 を使って勉強しています。 2次元配列を持つクラスを作ろうとしていますが、クラス定義ファイルの中のプライベート変数部分に2次元配列を定義しようとするとエラーメッセージが出てきます。 自分のソースコードは次のようなもので、最後の int aray[rowSize][colSize]; の部分に赤い波線が出ていて、そこにカーソルを合わせると「静的でないメンバー参照は特定のオブジェクトを基準とする相対参照である必要があります。」というメッセージが出ます。 #pragma once #ifndef DSUBARRAY_H // Double Subscripted Array #define DSUBARRAY_H #include <iostream> using namespace std; class DsubArray { public: friend ostream &operator<<(ostream &, const DsubArray &); // output array friend istream &operator>>(istream &, DsubArray &); // input array DsubArray(const int=1, const int=1); // default constructor DsubArray(DsubArray &); // copy constructor ~DsubArray(); // destructor int &operator()(int, int);// subscript -- lvalue const int &operator()(int, int) const; // subscript -- rvalue DsubArray &operator=(DsubArray &);// assignment bool operator==(DsubArray &) const; // equality check of the two arrays bool operator!=(DsubArray &) const; // inequality check int getRowSize() const; int getColSize() const; private: int rowSize; int colSize; int aray[rowSize][colSize]; }; #endif これをたとえば次のように書き換えると、赤い波線は消えるのですが、今度はコラムのサイズが10に固定されてしまい、コンストラクターでこれと異なる数値を与えるとエラーになってしまうのではないかと心配します。 int aray[ ][10]; どなたか2次元配列の正しい作り方を教えてください。お願いいたします。

  • 継承したポインタ

    まだ経験が浅いので単純な理屈だと思うのですが、納得できる資料がなかったのでどうかご教授お願いいたします。 class AAA { DATA *pData; }; class BBB : public AAA { ..... }; こんな感じのクラスを用意し、実体をメイン関数内で作ったんですが、 AAA aaa; BBB bbb; aaa.pData->Rendering(); これだと上手くいくのに bbb.pData->Rendering(); これだとアクセス違反になるのはなぜでしょうか?