Циркулярный заголовок C++ включает

В проекте у меня есть 2 класса:

//mainw.h

#include "IFr.h"
...
class mainw
{
public:
static IFr ifr;
static CSize=100;
...
};

//IFr.h

#include "mainw.h"
...
class IFr
{
public float[mainw::CSize];
};

Но я не могу скомпилировать этот код, получив ошибку в строке static IFr ifr;. Запрещено ли подобное перекрестное включение?

Ответы

Ответ 1

Запрещены ли такие кросс-включения?

Да.

Обход должен состоять в том, чтобы сказать, что член ifr mainw является ссылкой или указателем, так что декларация forward будет делать, а не включать полное объявление, например:

//#include "IFr.h" //not this
class IFr; //this instead
...
class mainw
{
public:
static IFr* ifr; //pointer; don't forget to initialize this in mainw.cpp!
static CSize=100;
...
}

В качестве альтернативы, определите значение CSize в отдельном файле заголовка (так что Ifr.h может включать этот другой файл заголовка вместо включения mainw.h).

Ответ 2

У вас не может быть двух классов, которые вставляют друг друга таким образом. Вы можете сделать один из них указателем:

class foo;

class bar 
{
    foo* fooPtr;
}

Вам нужно будет построить foo и назначить его fooPtr в конструкторе bar и освободить его в деструкторе - это определенно немного больше.

Или, в этом случае, как предложил один из комментаторов, make mainw:: size a define и поместите его где-то в общей сложности.

Ответ 3

Вы можете сделать рекурсивный, например, такой, но в целом вам также понадобится использовать какой-то трюк для защиты заголовка - иначе препроцессор перейдет в бесконечную рекурсию. Это не поможет вам решить вашу основную проблему, потому что у вас есть по существу два класса, каждый из которых обязательно требует полного декларирования другого для компиляции:

class mainw
{
public:
static IFr ifr; // needs to see the full declaration of the Ifr class in order to know the size
...

class IFr
{
public float[mainw::size]; // needs to see the full declaration of mainw in order to know what size is

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

Ответ 4

Такое круговое включение не допускается С++, но это должно работать:

Вместо включения IFr.h используйте декларацию forward.

class IFr;
class mainw
{
    //...
};

Это сделает компиляцию mainw просто прекрасной, но весь код, который использует член ifr, должен также включать IFr.h.

Это работает только потому, что ifr является членом static. В противном случае компилятор должен знать точный размер ifr.

Кроме того, как и многие другие люди, вы должны включить защитников обоим заголовкам, чтобы избежать ошибок, возникающих из-за включения одного и того же заголовка дважды.

#ifndef IFR_H
#define IFR_H
//...
#endif

Ответ 5

Вы можете сделать:

// mainw.h

#include "IFr.h"
class mainw {
public:
    static const size_t CSize=100;
    static IFr<CSize> ifr;
...
};

// IFr.h
template <size_t Sz>
struct IFr {
    float sz_[Sz];
};

Или в случае, если CSize необходимо изменить во время выполнения, используйте указатель-указатель, как показывает ответ @ChrisW.

Ответ 6

Если вы получили

#ifndef __MYHEADER_NAME_WHICH_IS_RANDOM_PER_FILE_H
#define __MYHEADER_NAME_WHICH_IS_RANDOM_PER_FILE_H
//... Code..
#endif

обернутый вокруг вашего кода, тогда вы должны быть в порядке:)

[EDIT] Написание кода: O: P