3つのクラスがあり、
・スーパークラス
メンバ変数にQWEクラスのポインタを保持
・サブクラス
QWEクラスのメンバ関数を実行する
・QWEクラス
サブクラスのポインタからメンバ関数を実行する
QWEクラスでサブクラスが定義されていませんと出たので
循環参照なのだろうとスーパークラスのQWEの宣言を
class QWE qwe;
と治し、#include "QWE.h"を消したのですが、
サブクラスで"QWEが定義されていません"のような節のエラーがでます。
どうしたら良いですか?
循環参照を回避できない
Re: 循環参照を回避できない
根本的にクラス設計がまずそうな気はしますが、取り敢えず3つのクラスの定義を見せていただけますか?
Re: 循環参照を回避できない
携帯なので多々誤字があるかもしれませんが・・÷
パソコンのモデムが死んでてコピペが一番だとは思うのですが直書きで失礼します。
流れはCPartクラスを継承した図形クラスがあるので其方をインスタンス化して
CContactListという当たり判定リストに登録します。
CContactList::Run()という関数があるのでそれを行うと
登録されたCPartが本来の図形にリキャストされて相互に判定を行い
結果をEntityBase::HitNotify()に、接触したCPartのポインタを返します
以上です。
わかりにくい・解決のために抜けている物があった場合すいません。
#include "EntityBase.h"
class CPart : public EntityBase{
Part(CContactList* tmpContactList){ContactList=tmpContactList;}
void func(){ContactList->Entry(this)}
};
#include "Part"
#include <vector>
using namespace std;
class CContactList{
vector<CPart*> List;
void Entry(CPart* tmp){List.push_back(tmp);}
};
流れはCPartクラスを継承した図形クラスがあるので其方をインスタンス化して
CContactListという当たり判定リストに登録します。
CContactList::Run()という関数があるのでそれを行うと
登録されたCPartが本来の図形にリキャストされて相互に判定を行い
結果をEntityBase::HitNotify()に、接触したCPartのポインタを返します
以上です。
わかりにくい・解決のために抜けている物があった場合すいません。
Re: 循環参照を回避できない
#include "EntityBase.h"
#include "Part.h"
#include <vector>
using namespace std;
class Entity:public EntityBase{
vector<CPart> Parts;
}
おそらくCContactListとこれ以外ではCPartとEntityBaseは使いません
ゲーム中の全てのオブジェクトはこれを継承して
建物やキャラを構成します。
ひょっとしたらこいつにPartをContactListに登録させれば循環参照は
起きないかもしれませんが
できることであればPartの振る舞いはPartにさせたいです
Re: 循環参照を回避できない
なるほど。拝見いたしました。
EntityBase#ContactList は要するに 親 みたいな感じですね。自分を含むリストへの参照。
これ自体は良くある設計なので良いと思います。
ではいくつか。
ポインタ型しか使わない場合、class宣言だけでOKです しかし、ポインタ経由でメソッド呼び出しなどをする時点では実装が見えてないといけません。 とまあこんな感じですね。
EntityBase#ContactList は要するに 親 みたいな感じですね。自分を含むリストへの参照。
これ自体は良くある設計なので良いと思います。
ではいくつか。
ポインタ型しか使わない場合、class宣言だけでOKです しかし、ポインタ経由でメソッド呼び出しなどをする時点では実装が見えてないといけません。 とまあこんな感じですね。
Re: 循環参照を回避できない
これを元に AXL さんのプログラムの改良点を示すと
- まず、クラスの実装を hpp と cpp に分けます。
- hpp にはメンバ変数の宣言と、メンバ関数のプロトタイプ宣言だけを書きます。
その際、できるだけ #include は少なくして、 class 何とか; の宣言だけで済ませるようにします。
(つまり、ポインタ型しか使わないようなクラスは全部 class 何とか; の形で済ませます。今回の場合は CContactList と CPart です。ただし標準ライブラリのクラスは普通に#includeしましょう) - cpp にはメンバ関数の定義を書きます。
その際、 hpp で class 何とか; したクラス定義を全部 #include します。
Re: 循環参照を回避できない
>beatleさん
返答ありがとうございます。
>しかし、ポインタ経由でメソッド呼び出しなどをする時点では実装が見えてないといけません。
なるほど、EntityBase.hでは"何かのクラス"という情報だけで、EntityBase.cppでContactList.hをincludeすれば回避できそうですね
USBメモリ持ってネットカフェに来たのでソースコードを貼らせて頂きます。^^;
せっかく、と言っては回答してくれる方に失礼かもしれませんが、これはまずいというようなところがありましたらご指摘お願いします。
※記述中に登場するCObjectはPosX,PosY,AngleとGetSetのみの構成です。
EntityBase.h
Part.h
ContactList.h
返答ありがとうございます。
>しかし、ポインタ経由でメソッド呼び出しなどをする時点では実装が見えてないといけません。
なるほど、EntityBase.hでは"何かのクラス"という情報だけで、EntityBase.cppでContactList.hをincludeすれば回避できそうですね
USBメモリ持ってネットカフェに来たのでソースコードを貼らせて頂きます。^^;
せっかく、と言っては回答してくれる方に失礼かもしれませんが、これはまずいというようなところがありましたらご指摘お願いします。
※記述中に登場するCObjectはPosX,PosY,AngleとGetSetのみの構成です。
EntityBase.h
#ifndef DEF_EntityBase
#define DEF_EntityBase
#include "Object.h"
#include "ContactList.h"
#include <string>
using namespace std;
class CEntityBase : public CObject{
protected:
string Name;
int HitPoint;//PartにもHPを持たせて部位破壊を表現したい
//子クラスのコンストラクタで決定してください。
CContactList* ContactList;
public:
CEntityBase();
void SetName(string);
void SetHitPoint(int);
string GetName();
int GetHitPoint();
virtual void BattleNotifi()=0;
};
#endif
/*
EntityBase→Part
↓ ↓
Entity <- 各種形状
↓
各種オブジェクト
→継承
->保持
*/
#ifndef DEF_Part
#define DEF_Part
#include "EntityBase.h"
//形状クラスはこれを継承する。
//Minecraftのようにダメージの種類によってメンバ関数を作成することはしない。
class CPart : public CEntityBase{
protected:
//このPartを持つ親です。中身はEntityを継承したクラスになります。
//子クラスのコンストラクタで決定してください。
CEntityBase* ParentEntity;
//このPartのEntityから見た識別子
int Identifier;
//このPartの形状
//子クラスのコンストラクタで決定してください。
int Shape;
//部位が担当するイメージ
int ImageHandle;
//加害
bool PerpetratorFlag;
//被害
bool VictimFlag;
//接触
bool ContactFlag;
//描画
bool DrawFlag;
public:
CPart();
//加害
void SetPerpetratorFlag(bool);
//被害
void SetVictimFlag(bool);
//接触
void SetContactFlag(bool);
void SetImageHandle(int);
//描画
void SetDrawFlag(bool);
//識別子の設定
void SetIdentifier(int);
//識別子の取得
int GetIdentifier();
//形状の取得
int GetShape();
void Draw();
void ContactListEntry();
//PartではContactMapから呼び出されます。
void BattleNotifi();
};
#endif
#ifndef DEF_ContactList
#define DEF_ContactList
#include "Part.h"
#include "const.h"
#include <vector>
using namespace std;
//攻撃Partから被害Partに総当り判定を行い、結果を返します。
//また、渡された接触Partが1フレーム前の接触リストの接触エンティティと接触しているかどうかを判定します。
class CContactList{
private:
//加害エンティティ
vector<CPart*> PerpetratorList;
//被害エンティティ
vector<CPart*> VictimList;
//接触エンティティ
vector<CPart*> NewContactList;
vector<CPart*> ContactList;//1フレーム前のPartの状態
//当たっていたらtrueを返します。bool値は各オブジェクトに攻防通知をします。衝突の場合しません。距離、角度
bool (CContactList::*Judge[SHAPENUM][SHAPENUM])(CPart*,CPart*,double*); //関数ポインタ配列
bool JudgeLineCircle(CPart*,CPart*,double*);
bool JudgeCircleLine(CPart*,CPart*,double*);
bool JudgeCircleCircle(CPart*,CPart*,double*);
bool JudgeLineLine(CPart*,CPart*,double*);
public:
CContactList();
void CombatRun();
//1フレーム前の接触判定と現在のPartが接触していないかを確かめる
//接触していた場合、返り値として接触対象のPartを返し、受け取ったEntityが反応を決めます。
bool ContactCheck(CPart*,double*);
void ContactListEntry(CPart*,bool,bool,bool);
};
#endif