Взаимное включение в C++. как это работает? [дубликат]

Возможные Дубликаты:
правильный способ #include, когда есть круговая зависимость?

Я довольно новичок в C++ и имею вопрос, заданный в названии. Или точнее: если A. h включает B. h и B. h включает A. h, я получаю сообщение об ошибке, потому что "include# file" C:...А. Ч." включает в себя". Файл: B. h

Я не мог найти способ обойти это, и моя общая настройка в значительной степени требует, чтобы отношения между этими классами. Есть возможность сделать это?

7 ответов


простой: не позволяйте A. h включать B. h. И наоборот.

В общем, заголовочные файлы должны содержать как можно. Вы можете использовать forward объявление, чтобы обойти много включает. Единственный раз, когда вы абсолютно должны включить что-то в заголовок, - это если в этом заголовке есть объекты, которые используются как не ссылки.

поэтому избегайте этого. Используйте Pimpl, чтобы не помещать членов класса в заголовки. И если это не код шаблона или вам не нужен поддержка inlining, не пишите фактический код в заголовках.

в худшем случае вам нужно будет создать C. h, который определяет, что нужно A. h и B. h.


используйте Include guards в файлах заголовков. http://en.wikipedia.org/wiki/Include_guard

#ifndef MYHEADER_H
#define MYHEADER_H

//add decls here 

#endif

таким образом, если ваши заголовочные файлы включены более одного раза, компилятор игнорирует их.

также, как правило, если вы включаете B. h, который имеет A. h, было бы лучше включить A. h и B. h в ваше приложение вместо того, чтобы полагаться на включение B. h.

также только помещать объявления в заголовочный файл .

избежать Определения любой ценой в заголовочных файлах.


вы не сказали, каковы эти взаимные зависимости, так что это просто догадки. Во всех из них я предполагаю, что A. h определяет class A и B. H определена class B.

корпус 1: взаимная зависимость через указатели или ссылки.
Например, class A содержит элемент данных типа B* и наоборот. В этом случае ни один заголовок не должен #include другие. Использовать упреждающее объявление.

корпус 2: взаимное зависимость между объектами.
Например, class A содержит элемент данных типа B и наоборот. В этом случае вы обливаетесь из шланга.

корпус 3: смешанный зависимостей.
Например, class A содержит элемент данных типа B но class B содержит элемент данных типа A*. Теперь A. h нужно #include B.h, но B. h просто нуждается в прямом заявлении class A.

вы всегда должны использовать какой-то один раз включить защитите, чтобы предотвратить заголовок от включения несколько раз.


предполагая, что в каждом заголовке, у вас есть класс, вы можете сделать так:

файл заголовка: "A. h"

#ifndef A_H
#define A_H
Class B;

Class A {
public:
  B name_of_B_;
}

#endif

С #ifndef A_H #define A_H #endif убедитесь, что каждый заголовок включен только один раз. Вы должны использовать это практически в каждом файле заголовка, который вы создаете, а не только в этом частном случае двойного включения. С Class B; вы объявляете, что где-то будет определен класс с именем "B".

Class B {
public:
  A name_of_A_;
}

#endif

та же история, что и для класса "B". Таким образом, вы избегаете бесконечное включение цикла.


У вас Циклическая Зависимость. Его можно решить с помощью Включить Охранников.


попробуйте добавить защиту заголовка,

#ifndef _A_H_
#define _A_H_
...
..
.
#endif /* #ifndef _A_H_ */

вы никогда не должны включать файл заголовка дважды, приводит к переопределению..


Если файл заголовка добавляется в файл, он включается во время предварительной обработки части компиляции. Так в том числе Б. Ч. В А. Н. И в том числе А. Ч. Б. Ч. Это своего рода бесконечно рекурсивные и файл включается несколько раз.

включая B. h в A. h составляет А. Ч. Ч. А. Ч. Б. Ч. составляет ЧД

таким образом, его король бесконечного рекурсивного цикла.