为什么这个错误不明确?

时间:2018-01-15 19:01:55

标签: c++ qt

我有以下代码:

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.hBar中的foo.h的前瞻性声明进行了修正。

我的问题是,为什么编译器会将此错误听起来像语法错误,而实际上并非如此?我认为捕获这样的错误并返回正确的错误消息将非常简单。

2 个答案:

答案 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不是作为成员名称而是作为构造函数的一种参数,因此完全猜错了。