3

私は基本的なエンティティ/オブジェクト管理システムをセットアップしようとしています.2つのクラスがあります.1つは継承元のエンティティの基本クラスであり、もう1つはそれらすべてを管理および制御します.

これは私が使用しようとしているソースコードです:

#include <iostream>
#define MAX_ENTS 400
class EFentity;
class EFiterator;
class EFentity {
     public:
          EFentity();
          virtual bool step();
          virtual void create(EFiterator*,int);
          virtual void destroy();
     private:
          int holder_id;
          EFiterator* holder;
};
EFentity::EFentity(void) {
     //    add base entity stuff
}
void EFentity::destroy() {
     holder->ents[holder_id]=NULL;
     std::cout << "destroying object id "<<holder_id;
     delete this;
}
void EFentity::create(EFiterator* h,int pos) {
     holder=h;
     holder_id=pos;
}
bool EFentity::step() {
     return false;
}
class EFiterator {
public:
     EFentity* ents[MAX_ENTS];
     int e_size;
     EFiterator();
     void push(EFentity* e);
     void update();
};
EFiterator::EFiterator() {
     e_size=0;
}
void EFiterator::update() {
     for(int i=0;i<e_size;i++) {
          if (!ents[i]->step()) {
               std::cout << "entity id "<< i<<" generated a fault!\n";
          } else std::cout << "entity id "<<i<<" passed step test.\n";
     }
}
void EFiterator::push(EFentity* e) {
     ents[e_size]=e;
     e->create(this,e_size++);
}
int main() {
     EFiterator main_iterator;
     main_iterator.push(new EFentity());
     main_iterator.update();
     std::cin.get();
     return 0;
}

このコードは明らかにコンパイルされません。エラーは次のとおりです。

In member function `virtual void EFentity::destroy()':

[20] invalid use of undefined type `struct EFiterator' 
[5] forward declaration of `struct EFiterator'

以前に SO でこのような問題を見たことがありますが、メンバー変数や他のクラスの関数へのアクセスを必要としなかったため、ポインターで簡単に解決できました。

内の配列にアクセスする関数をプロトタイプ化することで解決できると思いますEFiteratorが、トリッキーなクラス操作でこれをスムーズに行う方法はありますか?

4

2 に答える 2

3

EFentity::destroy() needs know concrete type of EFiterator when it calls

 holder->ents[holder_id]=NULL;

Put EFentity::destroy() after EFiterator definition should resolve the problem, for example, put it after EFiterator

void EFiterator::push(EFentity* e) {
     ents[e_size]=e;
     e->create(this,e_size++);
}

void EFentity::destroy() {
     holder->ents[holder_id]=NULL;
     std::cout << "destroying object id "<<holder_id;
     delete this;
}

Normally forward declare types in header file and include concrete type in .cpp file, which breaks circular include issue.

EFentity.h

class EFiterator;
class EFentity {
     public:
          EFentity();
          virtual bool step();
          virtual void create(EFiterator*,int);
          virtual void destroy();
     private:
          int holder_id;
          EFiterator* holder;
};

EFentity.cpp

#include "EFiterator.h"

EFentity::EFentity(void) {
     //    add base entity stuff
}
void EFentity::destroy() {
     holder->ents[holder_id]=NULL;
     std::cout << "destroying object id "<<holder_id;
     delete this;
}
void EFentity::create(EFiterator* h,int pos) {
     holder=h;
     holder_id=pos;
}
bool EFentity::step() {
     return false;
}
于 2013-02-05T00:55:17.227 に答える
1

問題は、型を前方宣言しEFIterator、定義がコンパイラに表示される前にそのメンバーにアクセスしようとしたことです。コンパイラが の定義を読み取るとき、が というメンバーを持っているEFentity::destroy()ことを知る必要があります。EFIteratorents

解決策は簡単です。次のように、定義の前に 2 つの宣言を置きます。

#include <iostream>
#define MAX_ENTS 400
class EFentity;
// Now we can refer to EFentity by pointer or reference.

class EFiterator {
public:
  EFentity* ents[MAX_ENTS];
  int e_size;
  EFiterator();
  void push(EFentity* e);
  void update();
};
// Now we can refer to EFiterator by pointer, reference, or value.

class EFentity {
public:
  EFentity();
  virtual bool step();
  virtual void create(EFiterator*,int);
  virtual void destroy();
private:
  int holder_id;
  EFiterator* holder;
};
// Now we can refer to EFentity by pointer, reference, or value.

EFiterator::EFiterator() {
  // ...

これで、 の宣言はEFiterator型をポインターとして参照できEFentity(UDT であること以外は何も知る必要はありません)、 の宣言はEFentityEFiteratorをポインターとして参照できます (UDT であること以外を知る必要もありませんEFiterator)。 . EFiteratorand宣言の順序は重要でEFentityはありません。次のように簡単に反転できます。

#include <iostream>
#define MAX_ENTS 400
class EFiterator;
// Now we can refer to EFiterator by pointer or reference.

class EFentity {
public:
  EFentity();
  virtual bool step();
  virtual void create(EFiterator*, int);
  virtual void destroy();
private:
  int holder_id;
  EFiterator* holder;
};
// Now we can refer to EFentity by pointer, reference, or value.

class EFiterator {
public:
  EFentity* ents[MAX_ENTS];
  int e_size;
  EFiterator();
  void push(EFentity*);
  void update();
};
// Now we can refer to EFiterator by pointer, reference, or value.

EFiterator::EFiterator() {
  // ...

定義に到達するまでは、前の宣言を使用可能にする必要はありません。

于 2013-02-05T01:05:51.850 に答える