Как пользователь Шон Монро указал на использование header
или include guards
;это не всегда может быть полный ответ.Во многих случаях это поможет исправить вашу текущую проблему, но если вы не будете осторожны, вы можете стать жертвой циркулярных включений.
Прежде чем я упомяну что-либо об этом, я кратко опишу различия между #include <someheader.h>
и #include "someheader.h"
.Первый будет смотреть, где находится большая часть файлов вашей системы, операционной системы, компилятора и стандартных библиотек с помощью системных переменных среды, которые по умолчанию устанавливаются через вашу IDE.Последний будет искать любые непосредственные каталоги, которые настроены во включаемых путях для текущего проекта с корневым путем, где находится код, когда он создается при работе в Visual Studio;другие IDE, скорее всего, будут другими, но концепция все та же.
В циркулярном письме: иногда недостаточно иметь только защиту заголовков.Возьмем для примера:
file a.h
#ifndef A_H
#define A_H
#include "b.h"
class A {
private:
B b;
public:
explicit A( const B& b ) { ... }
};
#endif
file b.h
#ifndef B_H
#define B_H
#include "A.h"
class B {
public:
explicit( A* pA ) { ... }
};
#endif
Здесь это будет генерироватькруговое включение, и это очень важно знать.Независимо от того, какой класс A
или B
вы пытаетесь создать объект в каком-либо другом файле, пространстве имен, классе или функции, компилятор попытается создать первый класс, и для этого ему нужно создать второй класс.однако, пытаясь создать второй класс для завершения первого класса, он возвращается и пытается создать первый класс снова, поскольку следующий требует первого, который является неполным объектом, и наоборот.Это не совсем циклическое включение, скажем, это круговая бесконечная рекурсия зависимостей неполных классов.Вы можете прочитать это Q / A для получения дополнительной информации: Разрешить циклические зависимости .
Иногда недостаточно просто включить соответствующий заголовок одного класса в заголовок другого;иногда вам может понадобиться просто объявить class prototype
и или forward declaration
в заголовке класса, а затем включить файл заголовка в файл cpp
этого класса.Но это обычно будет работать чаще всего с pointers
или references
, но не с локальными копиями, поскольку pointers
и references
адресуются областью памяти, которая имеет фиксированный размер в памяти.Пример:
file A.h
#ifndef A_H
#define A_H
class B;
class A {
private:
B* pB;
public:
explicit A( const B& b );
};
#endif
file A.cpp
#include "A.h"
#include "B.h"
A::A( const B& b ) { ... }
file B.h
#ifndef B_H
#define B_H
#include "A.h"
class B {
public:
B(){ ... }
/*param type*/ someFunc( A* pA ) { /* do something with pA */ }
};
Есть больше проблем, чем обсуждается здесь, но вы можете прочитать о них в некоторых других ответах на ту же ссылку, что я предоставил выше.