C ++错误:“'class'没有命名类型”和“无效使用不完整类型'struct ...'”

时间:2014-01-09 16:39:44

标签: c++ types compilation include cyclic-dependency

这是一个非常重复的问题,也在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之前,作为附加信息,已经在此计划中与mainfoo完美配合。

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

4 个答案:

答案 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中的包含。

再次感谢; - )