这是一个非常重复的问题,也在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中,但我总是遇到某种错误。在最后一种情况下,我得到:
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
完美配合。
有用的想法吗?非常感谢:)
答案 0 :(得分:1)
在foo.h中
#pragma once //(or use a guard symbol)
class bar;
class foo
{
bar & bind(bar & b);
};
在bar.h中
#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
}
答案 1 :(得分:1)
这对我来说编译正常(注意:这没有实例化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
FILE 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
MAIN .cpp文件包含:
#include "foo.h"
#include "bar.h"
答案 2 :(得分:0)
C ++ 编译器非常老,而且,在代码中处理此示例的部分不是编译器本身,而是编译器链的一部分,称为预处理器< / em>的。如果我们同意 C ++ 编译器不是很聪明,那么预处理器就是一个枯燥但友好的助手。
编译了一个* .cpp文件,然后将其与程序中的其他* .cpp文件链接起来。 .h文件实际上没有任何意义:这种分离对于程序员来说应该是一个优势。这里的关键点在于,无论您在* .cpp文件中包含多少* .h文件,最终都会有一个巨大的生成的cpp文件,其中包含* .h文件中存在的整个代码,以及源代码存在于* .cpp文件中。
循环依赖可以通过多种方式解决,但是,正如您可以想象的那样,编译器甚至没有机会在问题产生之前处理任何事情。 C或C ++不支持循环依赖。
更多现代编译器,例如 Java 或 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()
{
// ...
}
前向声明可以让编译器知道该类实际上将存在,并且您正在声明其存在,但不提供有关其内容的详细信息。这就是为什么你可以在另一个类中使用这个前向声明作为指针(或引用)的原因(编译器需要转发类的大小才能创建一个属性,并且&#39;没有细节也是不可能的。)
此处还有其他概念可用,例如编译器保护。
希望这有帮助。
答案 3 :(得分:0)
非常感谢你们的答案。在许多方面,他们都很有帮助。
最后我意识到我必须在我的代码中对所有#include
重新排序,因为,正如您可能已经意识到的那样,有更多的编码,我在这里放的是一个更简单的版本(对不起)。
所以,我的最终解决方案是在class bar;
和foo.h
class foo;
中加入bar.h
。然后重新排序main.cpp
和Makefile中的包含。
再次感谢; - )