使用不完整的结构体类型是无效的,即使进行了前向声明。

15

我知道循环依赖的问题,但是即使使用了前置声明,我仍然遇到了这个错误。 我做错了什么?

// facility.h
class Area;

class Facility {
public:
    Facility();
    Area* getAreaThisIn();
    void setAreaThisIsIn(Area* area);
private:
    Area* __area;
};

// facility.cpp
#include "facility.h"
#include "area.h"
{ ... }

// area.h
class Facility;
class Area {
public:
    Area(int ID);
    int getId();

private:
    std::list<Facility*> _facilities;
};

// area.cpp
#include "area.h"
#include "facility.h"

所以这个代码能够编译通过,但如果我执行

// foo.h
#include "facility.h"
class Foo { .. };

// foo.cpp
#include "foo.h"
void Foo::function() {
    Facility* f = new Facility();
    int id = f->getAreaThisIsIn()->getId();

当我遇到 invalid use of incomplete type struct Area 错误时


3
你在定义 Foo::function() 的文件中是否包含了 area.h - James McNellis
我已经尝试使用g++编译它(添加了“Facility”和“Area”方法的存根定义),并在纠正了“facility.h”中的“getAreaThisIn()”拼写错误后进行了编译(应该是“getAreaThisIsIn()”)。对我来说,它已经编译成功了。虽然我的“Foo.cpp”确实包含了这两个头文件。 - QuantumMechanic
3
请注意,以双下划线(__area 就是其中之一)开头的标识符被实现保留,不应该被使用。 - Mark B
注意:我会编辑掉拼写错误,但由于这篇文章主要是代码,所以除非我重写整个问题,否则它不会让我这样做。 - robev
3个回答

25
为了澄清:前向声明允许您以非常有限的方式操作对象:
struct Foo; // forward declaration

int bar(Foo* f); // allowed, makes sense in a header file

Foo* baz(); // allowed

Foo* f = new Foo(); // not allowed, as the compiler doesn't
                    // know how big a Foo object is
                    // and therefore can't allocate that much
                    // memory and return a pointer to it

f->quux(); // also not allowed, as the compiler doesn't know
           // what members Foo has

前置声明在某些情况下是有帮助的。例如,如果头文件中的函数只需要指向对象的指针而不是对象本身,则无需为该头文件#include整个类定义。这可以提高编译时间。但是,该头文件的实现几乎肯定需要#include相关定义,因为您可能想要分配这些对象、调用这些对象的方法等等,而这需要更多的内容来完成。


8
对于 Facility* f = new Facility();,你需要一个完整的声明,而不仅仅是前置声明。

1
@robev 包含 facility.h 应该没有问题,除非还有其他错误。 - Šimon Tóth
1
@robev - 如果您展示Foo类的头文件和源代码文件,事情就会变得清晰明了。 - Mahesh
1
是的,你需要。仅包括facility.h只引入了Area的前向声明。但是由于你正在使用Area的方法,所以需要引入完整的Area声明。根据你的设置,这意味着你必须包含area.h文件。 - QuantumMechanic
1
@robev 如果你想要面积,就包括面积;如果你想要设施,就包括设施,就这么简单。 - Šimon Tóth
1
-1:在 int id = f->getAreaThisIsIn()->getId(); 中出现错误。因为调用 getId() 需要了解 Area 的信息。所以在这里包含 area.h 是必要的...而不是为了创建 Facility 的实例! - mmmmmmmm
显示剩余2条评论

4

你是否在foo.cpp(假设是出现错误的文件)中都包含了area.h和facility.h?


3
是的,由于您在代码中调用了Area和Facility实例的成员函数,所以必须这样做。 - Frank Schmitt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接