How do I define C ++ classes with circular dependencies?

I am trying to create a basic object / object management system and I have two classes, one for the base class for the entities to inherit from, and one for managing and managing them.

This is the original code I am trying to use:

#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;
}

      

This code obviously doesn't compile and here are the errors:

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

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

      

I've seen problems like this on SO before, but they didn't require access to member variables and functions of another class, so it could be easily solved with a pointer.

I think it can be solved by having a prototyped function to access the array internally EFiterator

, but is there a way to do this smoothly with some tricky class manipulation?

+3


source to share


2 answers


EFentity::destroy()

needs to know the specific type EFiterator

when it calls

 holder->ents[holder_id]=NULL;

      

Put EFentity::destroy()

after EFiterator

definition should solve the problem, for example, put it afterEFiterator

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;
}

      

Usually forward ad types in a header file, and include the specific type in the file .cpp

that breaks down the issue circular include

.



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;
}

      

+3


source


The problem is that you have a forward-declared type EFIterator

and then tried to access its members before the definition is visible to the compiler. When the compiler reads the definition for EFentity::destroy()

, it needs to know what the EFIterator

named member has ents

.

The solution is easy to achieve: place two declarations in front of the definitions, for example:

#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() {
  // ...

      



Now the declaration for EFIterator

can refer to the type EFentity

as a pointer (it does not need to know anything else other than that it is a UDT), and the declaration for for EFentity

can refer to the type EFIterator

as a pointer (it also does not need to know anything other than this EFIterator

is a UDT). Ordering of the ads EFIterator

, and EFentity

it does not matter; you can just as easily invert them:

#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() {
  // ...

      

Until you get to the definitions, you need to have previous declarations.

+1


source







All Articles