C++ 棘手的继承类定义问题
-
09-09-2019 - |
题
在处理多个类(包括彼此)时,我收到此错误:
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() {}
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() {}
小时
#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;
}
开始于 主程序, ,我可以确定这是编译器看到的:
#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
所以, A当我们到达时, 的定义还不完整 乙. 。有人告诉我,有时您需要使用前向声明,然后移动 #包括 声明进入 .cpp 文件,但我对此没有任何运气。如果我尝试类似的操作,我只会收到额外的错误:
error: forward declaration of 'struct ClassName'
我想也许我只是没有在正确的地方做事。有人可以告诉我如何编译这段代码吗?非常感谢!
编辑:我想指出,这只是真实代码的抽象版本。我意识到没有任何参考 K 在 A 或者 乙 在 J, ,但是在真实的代码中是有的,我觉得它们是完全必要的。也许如果我对真实的类进行简要描述,有人可以帮助我重组或修复我的代码。
班级 A 是一个抽象节点类,充当图中节点的接口。班级 乙 是许多不同实现之一 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() {}
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() {}
小时 (具体访客)
#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;
}
我必须添加一些前向声明,以使出现的一些其他错误(当我添加详细信息时)消失。其中一些可能不是必要的或不正确的。
解决方案
圆形的夹杂物不工作。
尽量保持夹杂物控制在最小值。如果你这样做,你要么被罚款完全,或者你会发现在你的设计问题。在你的情况,我看不出有什么不对您的设计。
当定义类K,你只使用一个指针到类型B的一个目的即不需要B到被定义(如“包含头文件”)中,仅被宣布(向前声明是细)。所以,在你的情况下,删除列入标题“B.h”改为“B类”;足够了。 (这同样适用类J)的
其他提示
您头夹杂物是圆形的。 A - >的K - >的J - >乙 - > A.使用前向声明是为了避免这种复杂性的最简单的方法,但所声明的类时,只使用引用或指针被包含在类只可能。你不能在K.h或B.h使用前声明,例如,因为他们自J和A分别继承。但是,你可以根据你如何在实际使用#include "K.h"
与class K;
K
更换A
在A.H。
谈论混乱。
在本具体例中,删除
#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"
from A.h
。
重要强>
当然需要添加所需的包括在各个相应CPP文件:
(J.cpp)
#include "B.h"
// ...
// Go ahead with implementation of J
// ...
(同为A.cpp
,包括K.h
)
的主要问题是,你的头文件包括彼此以圆形方式。一个包括K个,其中包括j,它包括B-然后包括再......你不应该要求的情况下发生这种情况。你应该回到设计画板要么削减一些依赖,或者完全重新组织类,以便该循环依赖不会发生。
问题在于您的头文件循环相互依赖。不包括 K.h
在 A.h
和 B.h
在 J.h
. 。那里不需要他们。
关于您的编辑:这不是对象交互的最佳方式。重新思考你的设计。谁打电话 node.accept(visitor)
?你不能打电话吗 visitor(node)
直接地?
另外,如果您想设计一个图形库,请看看 Boost.Graph 图书馆。
也就是说,因为您只使用一个指针 B
在 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
}