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
// ...