【问题标题】:Circular Dependencies / Incomplete Types循环依赖/不完整类型
【发布时间】:2011-12-01 18:33:19
【问题描述】:

在 C++ 中,我遇到了循环依赖/不完整类型的问题。情况如下:

Stuffcollection.h

#include "Spritesheet.h";
class Stuffcollection {
    public:
    void myfunc (Spritesheet *spritesheet);
    void myfuncTwo ();
};

Stuffcollection.cpp

void Stuffcollection::myfunc(Spritesheet *spritesheet) {
    unsigned int myvar = 5 * spritesheet->spritevar;
}
void myfunc2() {
    //
}

Spritesheet.h

#include "Stuffcollection.h"
class Spritesheet {
    public:
    void init();
};

Spritesheet.cpp

void Spritesheet::init() {
    Stuffcollection stuffme;
    myvar = stuffme.myfuncTwo();
}
  • 如果我保留如上所示的包含,我得到编译器错误 spritesheet has not been declared 在 Stuffcollection.h(第 4 行 以上)。我理解这是由于循环依赖。
  • 现在,如果我将 #include "Spritesheet.h" 更改为 Forward 在 Stuffcollection.h 中声明 class Spritesheet;,我得到了 编译器错误invalid use of incomplete type 'struct Spritesheet' 在 Stuffcollection.cpp 中(上面的第 2 行)。
  • 同样,如果我在 Spritesheet.h 中将 #include "Stuffcollection.h" 更改为 class Stuffcollection;,我会收到编译器错误 aggregate 'Stuffcollection stuffme' has incomplete type and cannot be defined 在 Spritesheet.cpp 中(上面的第 2 行)。

我能做些什么来解决这个问题?

【问题讨论】:

  • 重复stackoverflow.com/questions/7665912/double-include-solution/…(这是同一作者不久前提出的!)
  • @EdHeal:我对那个 Q 有最高的投票答案,它不是重复的。有细微差别,仔细看就知道了。
  • 这不是您程序中的实际代码。此代码无法生成您指示的错误消息。请将您的程序缩减为一个最小的、完整的示例程序,并在此处复制粘贴(重新键入)该代码。见sscce.org
  • @Als - 我认为上一个问题对 .cpp 文件中的#include 来说是显而易见的。
  • @EdHeal:是的,但是 OP 不理解它,如果我们关闭这个重复的说法,他/她不会。

标签: c++ circular-dependency incomplete-type


【解决方案1】:

你应该在Stuffcollection.cpp中包含Spritesheet.h
只需在头文件而不是 cpp 文件中使用前向声明,即可解决头文件的循环依赖问题。源文件实际上没有循环依赖。

从你之前的Qhere,我相信Stuffcollection类被用在Spritesheet头文件的类声明中,因此上面提出了解决方案。

【讨论】:

  • 谢谢!让它工作真的让我的整个代码变得更简单,因为我现在终于可以删除我所有的解决方法(主要是复制的函数......)。关于第 3 段:我注意到我不需要将 Stuffcollection.h 包含到 Spritesheet.h 中,将其包含到 Spritesheet.cpp 中就足够了。
  • 刚刚注意到:其实这正是你所说的 :)
  • @Ben:很高兴你能让它工作,总是用一个 Q 发布所有相关信息,以帮助我们更好地回答你的 Q,就像在这种情况下你的第一个 Q 表示(因为你没有显示该文件中的代码但包含它)可能您需要包含。
【解决方案2】:

将此表单用于您的嵌套包含:

Stuffcollection.h

#ifndef STUFFCOLLECTION_H_GUARD
#define STUFFCOLLECTION_H_GUARD
class Spritesheet;
class Stuffcollection {
  public:
  void myfunc (Spritesheet *spritesheet);
  void myfuncTwo ();
};
#endif

Stuffcollection.cpp

#include "Stuffcollection.h"
#include "Spritesheet.h"

void Stuffcollection::myfunc(Spritesheet *spritesheet) {
  unsigned int myvar = 5 * spritesheet->spritevar;
}

void Stuffcollection::myfuncTwo() {
  //
}

Spritesheet.h

#ifndef SPRITESHEET_H_GUARD
#define SPRITESHEET_H_GUARD
class Spritesheet {
  public:
  void init();
};
#endif

Spritesheet.cpp

#include "Stuffcollection.h"
#include "Spritesheet.h"

void Spritesheet::init() {
  Stuffcollection stuffme;
  myvar = stuffme.myfuncTwo();
}

我遵循的一般规则:

  • 不要从包含中包含包含,伙计。如果可能,首选前向声明。
    • 例外:包括系统包括任何你想要的地方
  • 让 CPP 包含它需要的所有内容,而不是依赖于 H 递归地包含它的文件。
  • 始终使用包含防护。
  • 永远不要使用pragma

【讨论】:

  • 另一个好规则:每个 .cpp 都应该首先包含自己的 .h(所以我会在 Spritesheet.cpp 中切换包含的顺序)。这样,至少有一个 .cpp 包含任何 .h 之前没有任何内容,从而确保 .h 不会丢失任何包含。
  • 这种方式对我有用,我在其中包含了 Alan 关于首先包含与 cpp 对应的 h 的提示。非常感谢。
  • @Ben -- 请为对您有帮助的答案投票,并接受(通过单击复选标记)最有帮助的答案。
【解决方案3】:

Spritesheet.h 不需要包含Stuffcollection.h,因为Spritesheet 的类声明中没有使用Stuffcollection。将包含行移至Spritesheet.cpp,你应该没问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-17
    • 2016-11-09
    • 2018-07-17
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 2011-09-18
    相关资源
    最近更新 更多