1

在处理包括彼此在内的多个类时出现此错误:

error: expected class-name before '{' token

我知道发生了什么,但我不知道如何正确纠正它。这是代码的抽象版本:

#ifndef A_H_
#define A_H_

#include "K.h"

class A
{
    public:
        A();

};

#endif /*A_H_*/

A.cpp

#include "A.h"

A::A() {}

溴化氢

#ifndef B_H_
#define B_H_

#include "A.h"

class B : public A
{ // error: expected class-name before '{' token
    public:
        B();
};

#endif /*B_H_*/

B.cpp

#include "B.h"

B::B() : A() {}

Jh

#ifndef J_H_
#define J_H_

#include "B.h"

class J
{
    public:
        J();
};

#endif /*J_H_*/

J.cpp

#include "J.h"

J::J() {}

#ifndef K_H_
#define K_H_

#include "J.h"

class K : public J
{ // error: expected class-name before '{' token
    public:
        K();
};

#endif /*K_H_*/

K.cpp

#include "K.h"

K::K() : J() {}

主文件

#include "A.h"

int main()
{
    return 0;
}

main.cpp开始,我可以确定这是编译器看到的:

#include "A.h"

#ifndef A_H_
#define A_H_

#include "K.h"

#ifndef K_H_
#define K_H_

#include "J.h"

#ifndef J_H_
#define J_H_

#include "B.h"

#ifndef B_H_
#define B_H_

#include "A.h"

class B : public A
{ // error: expected class-name before '{' token

因此,当我们到达B时, A的定义并不完整。有人告诉我,有时您需要使用前向声明,然后将#include语句移动到.cpp文件中,但我对此没有任何运气。如果我尝试这样的事情,我只会得到额外的错误:

error: forward declaration of 'struct ClassName'

我想也许我只是没有在正确的地方做事。有人可以告诉我如何编译这段代码吗?非常感谢你!


编辑:我想指出这只是真实代码的抽象版本。我意识到在A中没有对KJ中的B的引用,但是在真实的代码中有,我觉得它们是完全必要的。也许如果我对真实类进行简要描述,有人可以帮助我重组或修复我的代码。

A类是一个抽象节点类,充当图中节点的接口。B类是A的许多不同实现之一。同理,J类是一个抽象的Visitor类,K是对应的实现。这是具有更多上下文的代码:

(抽象节点)

#ifndef A_H_
#define A_H_

#include "K.h"

class K;

class A
{
    public:
        A();

        virtual void accept(const K&) const = 0;
};

#endif /*A_H_*/

A.cpp

#include "A.h"

A::A() {}

Bh(具体节点)

#ifndef B_H_
#define B_H_

#include "A.h"

class K;

class B : public A
{ // error: expected class-name before '{' token
    public:
        B();

        virtual void accept(const K&) const;
};

#endif /*B_H_*/

B.cpp

#include "B.h"

B::B() : A() {}

void B::accept(const K& k) const { k.visit(this); }

Jh(抽象访问者)

#ifndef J_H_
#define J_H_

#include "B.h"

class B;

class J
{
    public:
        J();

        virtual void visit(const B*) const = 0;
};

#endif /*J_H_*/

J.cpp

#include "J.h"

J::J() {}

Kh(具体访客)

#ifndef K_H_
#define K_H_

#include "J.h"

class B;

class K : public J
{ // error: expected class-name before '{' token
    public:
        K();

        virtual void visit(const B*) const;
};

#endif /*K_H_*/

K.cpp

#include "K.h"

K::K() : J() {}

void K::visit(const B*) const {};

主文件

#include "A.h"

int main()
{
    return 0;
}

我必须添加一些前向声明以使出现的一些额外错误(当我添加细节时)消失。其中一些可能不是必需的或不正确的。

4

5 回答 5

6

您的标题包含是循环的。A -> K -> J -> B -> A。使用前向声明是避免这种复杂性的最简单方法,但只有在被声明的类仅使用引用或指向所包含类的指针时才有可能。例如,您不能在 Kh 或 Bh 中使用前向声明,因为它们分别继承自 J 和 A。但是,您可以将#include "K.h"in Ah替换为class K;取决于您实际使用Kin 的方式A

谈论混乱。

于 2009-04-12T08:27:10.177 回答
3

在这个具体的例子中,删除

#include "B.h"

从文件中J.h,因为那里不需要。如果这不起作用,我们需要更多关于如何J使用的细节B......

编辑

由于J仅使用指向 的指针B,因此建议保持不变:-):

#include "B.h"从中删除J.h并用前向声明替换它B

(J.h)
class B;

class J
{
  // ...
  virtual void visit(const B*) const = 0; // This will work with forward declaration
}

#include "K.h"A.h.

重要的

当然,您需要在相应的 CPP 文件中添加所需的包含:

(J.cpp)
#include "B.h"
// ...
// Go ahead with implementation of J
// ...

(对于A.cpp,包括相同K.h

于 2009-04-12T08:29:49.407 回答
2

问题是您的头文件周期性地相互依赖。不要包括K.hinA.hB.hin J.h。他们在那里不需要。

关于您的编辑:这不是您的对象交互的最佳方式。重新考虑您的设计。谁打电话node.accept(visitor)?不能visitor(node)直接打电话吗?

此外,如果您正在尝试设计图形库,请查看Boost.Graph库。

也就是说,由于您只使用指向Bin的指针J.h,因此您不必包含B.h,只需前向声明该类。

class B;

struct J
{
    virtual void visit(const B*) const = 0;
};

然后包含B.h在您的K.cpp文件中。

#include "K.h"
#include "B.h"

void K::visit(const B* b) const
{
    // use b here any way you want
}
于 2009-04-12T08:29:45.710 回答
2

主要问题是您的头文件以循环方式相互包含。A 包括 K ,其中包括 J ,其中包括 B ,然后又包括 A ......你永远不应该要求发生这种情况的情况。你应该回到设计图板,要么削减一些依赖关系,要么完全重新组织你的类,这样这种循环依赖关系就不会发生。

于 2009-04-12T08:31:06.157 回答
1

圆形夹杂物不起作用。

尽量将夹杂物控制在最低限度。如果你这样做,你要么完全没问题,要么你会发现设计中的问题。就您而言,我认为您的设计没有任何问题。

定义类 K 时,您只使用指向 B 类型对象的指针。这不需要定义 B(如“包含头文件”),只需声明(前向声明即可)。因此,在您的情况下,删除包含到标题“Bh”的内容,替换为“B 类;” 足够了。(J班也一样)

于 2009-04-12T10:18:13.857 回答