0

这是一个非常重复的问题,也在 StackOverflow 中,但即使尝试不同的答案,我也无法解决我的问题。所以,我有一些课程:

主.cpp:

#include "foo.h"
#include "bar.h"

...

富.h:

#include "bar.h"
class foo {
  foo();
  bar& bind(bar &b);
  gru& bind(gru &g);
};

酒吧.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。作为附加信息,barmain我添加foo.

有什么有用的想法吗?非常感谢 :)

4

4 回答 4

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
}
于 2014-01-09T16:48:03.680 回答
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

文件 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"
于 2014-01-09T16:51:28.063 回答
0

C++编译器非常古老,此外,在您的代码中处理此示例的部分不是编译器本身,而是编译器链的一部分,称为预处理器。如果我们同意C++编译器不是很聪明,那么预处理器就是一个乏味但友好的助手。

一个 *.cpp 文件被编译并随后与程序中的其他 *.cpp 文件链接。.h 文件本身实际上没有任何意义:这种分离据说对程序员来说是一个优势。这里的关键点是,无论您在 *.cpp 文件中包含多少 *.h 文件,最后都会生成一个巨大的、生成的 cpp 文件,其中包含您的 *.h 文件中存在的整个代码,以及*.cpp 文件本身中的源代码。

循环依赖可以通过多种方式解决,但是,正如您可以想象的那样,编译器甚至没有机会在问题产生之前处理任何事情。C 或 C++ 不支持循环依赖。

更现代的编译器,例如JavaC#,能够提取类的公共接口,并在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()
{
    // ...
}

前向声明可以让编译器知道该类实际上将存在,并且您正在声明它的存在,但不提供有关其内容的详细信息。这就是为什么你可以只在另一个类中使用这个前向声明作为指针(或引用)(编译器需要前向类的大小才能创建属性,如果没有细节这是不可能的)。

这里还有其他概念可以使用,例如编译器保护。

希望这可以帮助。

于 2014-01-09T16:53:34.403 回答
0

非常感谢你们的答案。在许多方面,他们很有帮助。

最后,我意识到我必须重新排序#include代码中的所有 ',因为正如您可能已经意识到的那样,还有更多的编码,而我放在这里的是一个更简单的版本(对此感到抱歉)。

所以,我的最终解决方案是包含class bar;infoo.hclass foo;in bar.h。然后重新排序包含在main.cpp和 Makefile 中。

再次感谢 ;-)

于 2014-01-10T09:13:54.293 回答