C++ C++;棘手的继承类定义问题
在处理多个类(包括彼此)时,我会遇到此错误:C++ C++;棘手的继承类定义问题,c++,inheritance,forward-declaration,C++,Inheritance,Forward Declaration,在处理多个类(包括彼此)时,我会遇到此错误: error: expected class-name before '{' token 我知道发生了什么,但我不知道如何正确地纠正它。以下是代码的抽象版本: A.h A.cpp B.h B.cpp J.h J.cpp K.h K.cpp main.cpp 从main.cpp开始,我可以确定编译器看到的是: #include "A.h" #ifndef A_H_ #define A_H_ #include "K.h" #ifndef K_H_
error: expected class-name before '{' token
我知道发生了什么,但我不知道如何正确地纠正它。以下是代码的抽象版本:
A.h
A.cpp
B.h
B.cpp
J.h
J.cpp
K.h
K.cpp
main.cpp
从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中没有对K的引用,在J中没有对B的引用,但是在真实的代码中有,我觉得它们是完全必要的。如果我简单描述一下真正的类,也许有人可以帮助我重新构造或修复代码 类A是一个抽象节点类,充当图中节点的接口。类B是a的许多不同实现之一。同样,类J是一个抽象的访问者类,K是相应的实现。下面是包含更多上下文的代码: A.h(抽象节点) A.cpp B.h(混凝土节点) B.cpp J.h(抽象访客) J.cpp K.h(混凝土访客) K.cpp main.cpp
我不得不添加一些转发声明,以使出现的一些额外错误(当我添加细节时)消失。其中一些可能是不必要的或不正确的。标题包含的内容是圆形的。A->K->J->B->A。使用前向声明是避免这种复杂性的最简单的方法,但只有当被声明的类只使用指向所包含的类的引用或指针时,才可能使用前向声明。例如,不能在K.h或B.h中使用前向声明,因为它们分别从J和A继承。但是,您可以将A.h中的
#include“K.h”
替换为类K代码>取决于您在A
中实际使用K
的方式
谈论混淆。您的标题包含的内容是圆形的。A->K->J->B->A。使用前向声明是避免这种复杂性的最简单的方法,但只有当被声明的类只使用指向所包含的类的引用或指针时,才可能使用前向声明。例如,不能在K.h或B.h中使用前向声明,因为它们分别从J和A继承。但是,您可以将A.h中的#include“K.h”
替换为类K代码>取决于您在A
中实际使用K
的方式
谈论混淆。问题是头文件之间周期性地相互依赖。不要在A.h
中包含K.h
,在J.h
中包含B.h
。那里不需要它们
关于编辑:这不是对象交互的最佳方式。重新考虑你的设计。谁调用node.accept(访问者)
?您不能直接呼叫访客(节点)
此外,如果您正试图设计一个图形库,请查看该库
也就是说,由于您只在J.h
中使用指向B
的指针,因此不必包含B.h
,只需向前声明类
class B;
struct J
{
virtual void visit(const B*) const = 0;
};
然后在K.cpp
文件中包含B.h
#include "K.h"
#include "B.h"
void K::visit(const B* b) const
{
// use b here any way you want
}
问题是头文件之间存在周期性的依赖关系。不要在A.h
中包含K.h
,在J.h
中包含B.h
。那里不需要它们
关于编辑:这不是对象交互的最佳方式。重新考虑你的设计。谁调用node.accept(访问者)
?您不能直接呼叫访客(节点)
此外,如果您正试图设计一个图形库,请查看该库
也就是说,由于您只在J.h
中使用指向B
的指针,因此不必包含B.h
,只需向前声明类
class B;
struct J
{
virtual void visit(const B*) const = 0;
};
然后在K.cpp
文件中包含B.h
#include "K.h"
#include "B.h"
void K::visit(const B* b) const
{
// use b here any way you want
}
在这个具体示例中,删除
#include "B.h"
从文件J.h
,因为在那里不需要它。如果这不起作用,我们需要更多关于J
如何使用B
的细节
编辑
由于J
仅使用指向B
的指针,因此建议保持不变:-):
从J.h
中删除#包括“B.h”
,并用B
的正向声明替换它:
(J.h)
class B;
class J
{
// ...
virtual void visit(const B*) const = 0; // This will work with forward declaration
}
同时从A.h
中删除#包括“K.h”
重要
当然,您需要在相应的CPP文件中添加所需的include:
(J.cpp)
#include "B.h"
// ...
// Go ahead with implementation of J
// ...
(与
A.cpp
相同,包括K.h
)在此具体示例中,删除
#include "B.h"
从文件J.h
,因为在那里不需要它。如果这不起作用,我们需要更多关于J
如何使用B
的细节
编辑
由于J
仅使用指向B
的指针,因此建议保持不变:-):
从J.h
中删除#包括“B.h”
,并用B
的正向声明替换它:
(J.h)
class B;
class J
{
// ...
virtual void visit(const B*) const = 0; // This will work with forward declaration
}
同时从A.h
中删除#包括“K.h”
重要
当然,您需要在相应的CPP文件中添加所需的include:
(J.cpp)
#include "B.h"
// ...
// Go ahead with implementation of J
// ...
(与
A.cpp
相同,包括K.h
)主要问题是头文件以循环方式相互包含。A包括K,其中i
#include "A.h"
A::A() {}
#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_*/
#include "B.h"
B::B() : A() {}
void B::accept(const K& k) const { k.visit(this); }
#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_*/
#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_*/
#include "K.h"
K::K() : J() {}
void K::visit(const B*) const {};
#include "A.h"
int main()
{
return 0;
}
class B;
struct J
{
virtual void visit(const B*) const = 0;
};
#include "K.h"
#include "B.h"
void K::visit(const B* b) const
{
// use b here any way you want
}
#include "B.h"
(J.h)
class B;
class J
{
// ...
virtual void visit(const B*) const = 0; // This will work with forward declaration
}
(J.cpp)
#include "B.h"
// ...
// Go ahead with implementation of J
// ...