在处理包括彼此在内的多个类时,我遇到了这个错误:
error: expected class-name before '{' token
我看到发生了什么,但我不知道如何正确纠正它。这是代码的抽象版本:
A.H
#ifndef A_H_
#define A_H_
#include "K.h"
class A
{
public:
A();
};
#endif /*A_H_*/
A.cpp
#include "A.h"
A::A() {}
B.h
#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() {}
J.H
#ifndef J_H_
#define J_H_
#include "B.h"
class J
{
public:
J();
};
#endif /*J_H_*/
J.cpp
#include "J.h"
J::J() {}
K.h
#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() {}
的main.cpp
#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'
我想也许我只是不在正确的地方做事。有人可以告诉我如何编译这段代码吗?非常感谢你!
编辑:我想指出这只是真实代码的抽象版本。我意识到在 J 中的 A 或 B 中没有对 K 的引用,但实际上有代码,我觉得他们是完全必要的。也许如果我简要介绍一下真正的类,有人可以帮我重构或修改我的代码。
类 A 是一个抽象节点类,充当图中节点的接口。类 B 是 A 的许多不同实现之一。同样,类 J 是一个抽象的Visitor类, K 是相应的实现。以下是具有更多上下文的代码:
A.h (抽象节点)
#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() {}
B.h (具体节点)
#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); }
J.h (摘要访客)
#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() {}
K.h (具体访客)
#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 {};
的main.cpp
#include "A.h"
int main()
{
return 0;
}
我不得不添加一些前向声明来使一些额外的错误(当我添加细节时)消失。其中一些可能没有必要或不正确。
答案 0 :(得分:6)
您的标题包含是圆形的。 A - > K - > J - > B - >答:使用前向声明是避免这种复杂性的最简单方法,但只有当声明的类仅使用对包含的类的引用或指针时才有可能。例如,您不能在K.h或B.h中使用前向声明,因为它们分别从J和A继承。但是,您可以使用#include "K.h"
替换A.h中的class K;
,具体取决于您在K
中实际使用A
的方式。
谈论混乱。
答案 1 :(得分: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
)
答案 2 :(得分:2)
问题是您的标头文件周期性地相互依赖。请勿在{{1}}中加K.h
,在A.h
加B.h
。那里不需要它们。
关于您的编辑:这不是对象进行交互的最佳方式。重新思考你的设计。谁致电J.h
?你不能直接打电话给node.accept(visitor)
吗?
另外,如果您正在尝试设计图表库,请查看Boost.Graph库。
也就是说,由于您只使用指向visitor(node)
中B
的指针,因此您不必包含J.h
,只需向前声明该类。
B.h
然后在class B;
struct J
{
virtual void visit(const B*) const = 0;
};
文件中添加B.h
。
K.cpp
答案 3 :(得分:2)
主要问题是您的头文件以循环方式相互包含。 A包括K,其中包括J,其中包括B,然后再包括A ......你永远不应该要求发生这种情况。您应该回到设计绘图板并切断一些依赖项,或者完全重组您的类,以便不会发生这种循环依赖。
答案 4 :(得分:1)
圆形内含物不起作用。
尽量将夹杂物保持在最低限度。如果你这样做,你可以完全没问题,或者你会发现你的设计出现问题。在您的情况下,我认为您的设计没有任何问题。
当定义类K时,你只使用指向类型B的对象的指针。这不需要定义B(如“包含头文件”),只是要声明(前向声明很好) )。因此,在您的情况下,删除包含标题“B.h”替换为“B类”;足够了。 (同样适用于J级)