我有以下代码:
foo.h中
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class Foo
{
public:
Foo(Bar bar);
};
#endif //FOO_H
bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class Bar
{
public:
Bar(Foo foo);
};
#endif //BAR_H
如果我编译它,我收到以下错误消息:
expected ')' before 'foo' bar.h line 9
在浏览本网站后,我使用Foo
中的bar.h
和Bar
中的foo.h
的前瞻性声明进行了修正。
我的问题是,为什么编译器会将此错误听起来像语法错误,而实际上并非如此?我认为捕获这样的错误并返回正确的错误消息将非常简单。
答案 0 :(得分:3)
您的标头包含未解析的循环依赖关系。那时你的代码在某处包含“foo.h”,然后在预处理之后就会变成
class Bar // expanded from #include "bar.h"
{
public:
Bar(Foo foo); // Foo is not declared at this point
};
class Foo // rest of foo.h content
{
public:
Foo(Bar bar);
};
如果您的代码首先包含“bar.h”,那么在预处理后它将变为
class Foo // expanded from #include "foo.h"
{
public:
Foo(Bar bar); // Bar is not declared at this point
};
class Bar // rest of bar.h content
{
public:
Bar(Foo foo);
};
因此两种情况都有错误。
要解决此问题,您需要使用正确的前向声明:
// foo.fwd.h
#ifndef FOO_FWD_H
#define FOO_FWD_H
class Foo;
#endif // FOO_FWD_H
// bar.fwd.h
#ifndef BAR_FWD_H
#define BAR_FWD_H
class Bar;
#endif // BAR_FWD_H
并将它们包含在标题中,而不是包含完整类声明的标题:
// foo.h
#ifndef FOO_H
#define FOO_H
#include "bar.fwd.h"
class Foo
{
public:
Foo(Bar bar);
};
#endif //FOO_H
// bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.fwd.h"
class Bar
{
public:
Bar(Foo foo);
};
#endif //BAR_H
然后将包含类定义的标头只包含在.cpp或实现文件中。
答案 1 :(得分:2)
C ++很难解析。当编译器不知道Foo
是某种类型的名称时,它期望我们尝试在Bar
中声明具有该名称的成员。代码不会解析成员声明的任何有效变体。
旧的编译器刚刚将这种情况诊断为“语法错误”。现代编译器试图变得更友好。诊断可能会试图帮助我们纠正这种(或其他类似的)有效成员声明之一的代码。
class Bar
{
public:
Bar (Foo());
Bar (*Moo);
Bar Roo();
};
不幸的是,由于Foo
不是作为成员名称而是作为构造函数的一种参数,因此完全猜错了。