Это очень повторяющаяся проблема, также здесь, в StackOverflow, но мне не удается решить мою проблему, даже пытаясь найти разные ответы. Итак, у меня есть несколько классов:
main.cpp:
#include "foo.h"#include "bar.h"
...
foo.h:
#include "bar.h"class foo {
foo();
bar& bind(bar &b);
gru& bind(gru &g);
};
bar.h:
#include "foo.h"class bar {
bar();
foo& bind(foo &f);
gru& bind(gru &g);
};
Ясно, что у меня есть циклическая зависимость. Так я получаю позорную ошибку 'bar' does not name a type
, В этом случае я добавляю class bar;
в foo
декларацию и удалить #include
, Когда я это делаю, я получаю: invalid use of incomplete type ‘struct bar'
,
Я пытался разными способами, также добавляя class foo;
в бар, но у меня всегда есть какая-то ошибка. В этом последнем случае я получаю:
bar.cpp:48:11: error: prototype for ‘foo& bar::bind(bar::foo&)’ does not match any in class ‘bar’
bar.h:55:12: error: candidates are: gru& bar::bind(gru&)
bar.h:54:13: error: bar::foo& bar::bind(bar::foo&)
Кроме того, я никогда не получаю жалоб gru
, Который, как дополнительная информация, уже был в этой программе, прекрасно работает вместе с bar
а также main
прежде чем я добавил foo
,
Есть полезные идеи? Большое спасибо 🙂
в foo.h
#pragma once //(or use a guard symbol)
class bar;
class foo
{
bar & bind(bar & b);
};
в бар.ч
#pragma once //(or use a guard symbol)
class foo;
class bar
{
foo & bind(foo & f);
};
в foo.cpp
#include <foo.h>
#include <bar.h>
bar foo:bind(bar & b)
{
// here you can use bar methods
}
в bar.cpp
#include <bar.h>
#include <foo.h>
foo bar:bind(foo & f)
{
// here you can use foo methods
}
Для меня это будет хорошо скомпилировано (ПРИМЕЧАНИЕ: это без создания экземпляра класса foo или bar):
ФАЙЛ bar.h СОДЕРЖИТ:
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class foo;
class gru;
class bar {
bar();
foo& bind(foo &f);
gru& bind(gru &g);
};
#endif
ФАЙЛ foo.h СОДЕРЖИТ:
#ifndef FOO_H
#define FOO_H
#include "bar.h"class bar;
class gru;
class foo {
foo();
bar& bind(bar &b);
gru& bind(gru &g);
};
#endif
ГЛАВНЫЙ .cpp ФАЙЛ СОДЕРЖИТ:
#include "foo.h"#include "bar.h"
Большое спасибо, ребята, за ответы. Во многом они были полезны.
В конце концов я понял, что мне нужно изменить порядок всех #include
Это в моем коде, потому что, как вы, возможно, поняли, кодирования было намного больше, и я поместил здесь более простую версию (извините за это).
Итак, мое окончательное решение было включить class bar;
в foo.h
а также class foo;
в bar.h
, Затем измените порядок включения в main.cpp
и Makefile.
Еще раз спасибо 😉
C ++ Компилятор очень старый, и, кроме того, часть, которая обрабатывает этот пример в вашем коде, является не самим компилятором, а частью цепочки компиляторов, известной как препроцессор. Если мы можем договориться о C ++ Компилятор не очень умен, препроцессор — скучный, но дружелюбный помощник.
Файл * .cpp компилируется, а затем связывается с другими файлами * .cpp в вашей программе. Файлы .h на самом деле сами по себе не имеют никакого значения: это разделение предположительно является преимуществом для программистов. Ключевым моментом здесь является то, что, независимо от того, сколько * .h файлов вы включили в ваш * .cpp файл, в конечном итоге будет просто огромный сгенерированный файл cpp, содержащий весь код, присутствующий в ваших * .h файлах, а также исходный код присутствует в самом файле * .cpp.
Циклическая зависимость может быть решена многими способами, но, как вы можете себе представить, компилятор даже не имеет возможности обработать что-либо до того, как возникнет проблема. Циклические зависимости не поддерживаются в C или C ++.
Более современные компиляторы, такие как Джава или же C #, могут извлечь открытый интерфейс классов и использовать эту информацию, когда A
класс нужен для B
класс и наоборот. Опять же, это невозможно в C ++.
Единственным решением было бы переписать ваш код. Целью является устранение циклического #include
директивы. На самом деле, если ваш код так же прост, как вы показываете здесь, вы можете легко решить его, используя предварительное объявление:
// foo.h
class bar;
class foo {
foo();
bar& bind(bar &b);
gru& bind(gru &g);
};
—
// bar.h
class foo;
class bar {
bar();
foo& bind(foo &f);
gru& bind(gru &g);
};
—
// main.cpp
#include "foo.h"#include "bar.h"
// ...
int main()
{
// ...
}
Предварительное объявление позволяет сообщить компилятору, что этот класс действительно существует, и вы объявляете о его присутствии впереди, но не сообщаете подробности о его содержимом. Вот почему вы можете просто использовать это прямое объявление для указателя (или ссылки) внутри другого класса (компилятору потребуется размер перенаправленного класса, чтобы иметь возможность создать атрибут, а это невозможно без подробностей).
Здесь работают другие концепции, такие как, например, защита компилятора.
Надеюсь это поможет.