如何转发声明用作成员变量的结构

时间:2011-08-04 11:50:48

标签: c++ compiler-errors forward-declaration

我在 Application.h

中定义了一个名为CardState的结构
#ifndef APPLICATION_H
#define APPLICATION_H

#include <Session.h> // Note that both files include each others

struct CardState {
    bool property1;
    bool property2;
};

class Application : public QApplication {

    Q_OBJECT

public:

    explicit Application(int argc, char *argv[]);

}

然后我在另一个文件中使用此CardState类型:

#ifndef SESSION_H
#define SESSION_H

#include <Application.h>

struct CardState;

class Session : public QObject {

    Q_OBJECT

public:

    void setCardState(const CardState& cardState);
    CardState cardState() const;

private:

    CardState cardState_;

};

}
#endif // SESSION_H

当包含 Session.h 时,似乎还没有包含 Application.h 所以我需要转发声明结构(参见上文)。但是,这还不够,在添加了前向声明之后,我仍然会收到此错误:

'Session::cardState_' uses undefined struct 'CardState'

如果我理解正确,那意味着编译器不知道如何初始化我的变量,因为CardState只是部分声明。我知道我可以通过使CardState成为指针来解决这个问题,而这通常就是我所做的,但还有其他更合适的方法来解决这个问题吗?

3 个答案:

答案 0 :(得分:4)

根据Oli Charlesworth的评论,这应该可以正常使用。

一般情况下,您可能想要:

  • CardState放在自己的标题中,然后在所有“客户端”标题中#include它,从而避免因这些标题的包含顺序而产生的任何复杂情况。
  • Session::cardState_声明为(智能)指针,避免需要实际的CardState声明。

- 编辑---

现在您已经编辑了代码,很明显存在循环包含依赖项,在这种情况下,您的代码确实不起作用,因此您必须应用上述解决方案之一。

答案 1 :(得分:1)

行。首先,您不需要在此处转发声明任何内容,因为您需要的结构在该头文件中完全声明。

无论如何,当你尝试这样做时,你最终会收到错误,可能是因为编译器认为你正在宣布新版本的CardState,然后它永远不会在任何地方获得完整的声明。

您需要做的是删除CardState的第二个(存根)延期,然后修复导致您(错误地)将该存根声明放入的错误。

在评论中,您说原始错误消息类似于“找不到标题”。对我而言,这意味着您可能没有编译器标准搜索库中包含Application.h的目录。如果您愿意,可以在命令行上使用-I dirname指令添加它。但很可能它与您的其他包含文件位于同一目录中,您只需将include语句更改为以下内容即可找到它:

#include "Application.h"  // Note quotes instead of <> 

更新:Laurent更新了示例代码,并在下面的评论中特别询问了指针。

首先,即使在更新的代码中,我也没有理由要求提出前向声明。只需将CardState的声明移到Session.h中,问题就会消失。像这样移动代码应始终是您的第一个解决方案。当你有相互引用的结构时,前向引用实际上只是 required

如果你确实有相互引用的结构,那么是的,你必须使这些字段中的至少一个成为指针或引用。这对编译器来说并不是真正的,因为它实际上可以实现结构。如果A实际上包含B的完整副本且B实际上包含A的完整副本,那么您的结构在逻辑上将具有无限大小!

答案 2 :(得分:1)

您具有循环依赖关系,循环依赖关系通过使用前向声明来解决。

一旦你转发声明,编译器只知道该类型存在;它没有关于其大小,成员或方法的任何信息。它被称为不完整类型。因此,您不能使用此类型(Incomlpete类型)来声明成员或基类,因为编译器需要知道该类型的布局。

是的,您必须将不完整类型作为指针。