Сложность построения решения для нескольких файлов

Я пытаюсь создать решение, которое имеет три файла. С main.cpp это четыре файла.

Entity.h

#pragma once

#include "SystemBase.h"
namespace Engine {

class Entity {
public:
Entity() { }

void s(SystemBase* sb) { }
};
}

SubscribersList.h

#pragma once

#include "SystemBase.h"#include "Entity.h"
namespace Engine {

class SubscribersList {
friend SystemBase;

public:
SubscribersList() { }

void f(Entity* e) { }
};
}

SystemBase.h

 #pragma once

#include "SubscribersList.h"#include "Entity.h"
namespace Engine {

class SystemBase {
public:
SystemBase() { }

void g(Entity* e) { }

private:
SubscribersList m;

};
}

Не сосредотачивайтесь на теле методов в заголовках. Это просто для простоты. Я нашел два способа создать решение.
1. Напишите слово класс перед всеми именами классов. Но происходит сбой, когда я пытаюсь отделить реализацию от прототипов.
2. Запишите весь код в одном файле.
Я не / не буду писать ключевое слово class перед всеми именами классов для построения решения, и, конечно, я не буду / не буду писать большой проект в одном файле. Так почему я не могу это построить? Что за магия ?!

0

Решение

Чтобы понять проблему зависимости циклического заголовка, нам сначала нужно понять разницу между объявлением и определением класса и концепцией неполных типов.

Прототип или предварительное объявление типа Type записывается как:

class Type;

Такое предварительное объявление позволяет создавать указатели и ссылки на этот тип.
Однако вы не можете создавать экземпляры, разыменовывать указатели или использовать ссылку на Type пока его полный тип не объявлен.

Декларация для Type может быть написано как:

class AnotherType;

class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};

Теперь у нас есть экземпляры объявлений, которые могут быть созданы, и указатели на Type может быть разыменовано.

Однако раньше m_theOtherThing разыменовывается или создается AnotherType должны быть полностью объявлены.

class AnotherType {
Type m_aType;
}

Должен сделать, что дает нам как полную декларацию и определение AnotherType,

Это позволяет продолжить писать определение Type::aMemberFunc:

void Type::aMemberFunc() {
m_theOtherThing = new AnotherType();
}

Если вместо того, чтобы представить этот код компилятору в этом порядке, мы вместо этого представили полные объявления Type а также AnotherType впереди:

class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};

class AnotherType {
Type m_aType;
}

затем AnotherType *m_theOtherThing; не скомпилируется как AnotherType не был объявлен или форвард объявлен этим пунктом.

Переключение заказа дает:

class AnotherType {
Type m_aType;
}

class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};

Сейчас Type m_aType; не будет компилироваться как Type не был объявлен. Предварительная декларация не подойдет в этом случае.

С помощью #pragma once вместо охранников заголовка ни в коем случае не меняет проблему. #pragma once только гарантирует, что заголовок будет включен, только если он не влияет на порядок, которым компилятор обрабатывает код в противном случае. Это, конечно, не позволяет компилятору игнорировать неопределенные типы, когда он достигает их.

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

0

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

Других решений пока нет …

По вопросам рекламы [email protected]