Заголовки включают и циклическую зависимость - PullRequest
1 голос
/ 26 января 2012

Мне интересно, почему код ниже не работает.В b.cpp класс B использует класс A, но он терпит неудачу, потому что объявление класса A не найдено.Тем не менее, a.hpp включен только раньше.Почему #include "a.hpp" здесь не работает?

Спасибо за любую помощь!

//===============================================
//file: a.hpp
//===============================================
#ifndef _A_HPP
#define _A_HPP

#include "b.hpp"

class A{
    public:
        A();
        // others methods using B here
};

#endif


//===============================================
//file: a.cpp
//===============================================
#include "a.hpp"

A::A(){}


//===============================================
//file: b.hpp
//===============================================
#ifndef _B_HPP
#define _B_HPP

#include "a.hpp"

class B{
    public:
        B(A a);
};

#endif
//===============================================
//file: b.cpp
//===============================================
#include "b.hpp"

B::B(A a){}



SHELL$ g++ -c a.cpp
In file included from a.hpp:7,
                 from a.cpp:4:
b.hpp:11: error: expected ‘)’ before ‘a’

Ответы [ 6 ]

2 голосов
/ 26 января 2012

Вам нужно использовать Объявления пересылки , чтобы разорвать такую ​​циклическую зависимость.
Однако учтите, что после пересылки объявления типа этот тип становится Неполный тип для компилятора и существуют ограничения на использование типа Incomplete

1 голос
/ 26 января 2012

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

//===============================================
//file: b.hpp
//===============================================
#ifndef _B_HPP
#define _B_HPP

class A;

class B{
    public:
        B(A& a);
};

#endif
0 голосов
/ 26 января 2012

В A.hpp не включайте реализации B.hpp или inline A, которые вызывают методы B.

Используйте class B; в A.hpp (предварительное объявление), если вам нужно сослаться на B& или B*.

Вместо этого поместите те реализации A, которые вызывают методы B, в A.cpp и включите B.hpp в A.cpp.

0 голосов
/ 26 января 2012

Когда b.hpp включает a.hpp, _A_HPP уже определено, поэтому прекомпилятор игнорирует содержимое файла, поэтому в строке B(A a) компилятор не знает о A.

если вам действительно нужны эти включения, попробуйте переместить #include "b.hpp" в конец a.hpp (или объявить class A; в заголовке b.hpp).

0 голосов
/ 26 января 2012

Зачем вам нужен циклический #include такой? Если вам нужно, чтобы компилятор знал, что класс существует (так что это может быть параметр и так далее), просто объявите его следующим образом:

class A;

Не циклически включать файлы. Даже с охраной, они оба будут включены только один раз, конечно, но тогда вы все равно столкнетесь с упоминанием A до того, как компилятор доберется до его определения, или упоминанием B перед компилятором добирается до своего определения.

0 голосов
/ 26 января 2012

Удалите

#include "b.hpp"

из a.h и получите только предварительное объявление - при условии, что вы используете указатели на B в A:

//A.hpp

class B; //forward declaration

class A{
    public:
        A();
        // others methods using B here
};

Также: Имена макросов, начинающиеся с подчеркивания _, зарезервированы стандартом и не должны использоваться.Заменить _B_HPP на просто B_HPP.

...