Как определить классы C ++ с круговыми зависимостями?

Я пытаюсь настроить базовую систему управления сущностями / объектами, и у меня есть два класса, один для базового класса для сущностей, от которых можно наследовать, и один для управления и контроля над всеми ними.

Это исходный код, который я пытаюсь использовать:

#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, но есть ли способ сделать это гладко с некоторыми хитрыми манипуляциями с классом?

3

Решение

EFentity::destroy() необходимо знать конкретный тип EFiterator когда он звонит

 holder->ents[holder_id]=NULL;

Положил EFentity::destroy() после EFiterator определение должно решить проблему, например, поставить его после 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;
}

Обычно вперед объявляют типы в заголовочном файле и включают конкретный тип в .cpp файл, который ломается 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

Другие решения

Проблема в том, что вы заранее объявили тип EFIterator и затем попытался получить доступ к его членам, прежде чем определение станет видимым для компилятора. Когда компилятор читает определение для EFentity::destroy()нужно знать, что EFIterator имеет члена под названием ents,

Решение легко достичь: Поместите две декларации перед определениями, вот так:

#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), и объявление для EFentity может относиться к типу EFiterator в качестве указателя (также не нужно знать ничего, кроме этого EFiterator это UDT). Порядок EFiterator а также 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() {
// ...

Пока не доберешься до определения вам нужно иметь предыдущее декларации имеется в наличии.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector