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() {}
BH
#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() {}
Kh
#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
그래서, ㅏ우리가 도착하면의 정의가 완료되지 않습니다. 비. 나는 때때로 당신이 선언문을 사용하고 움직여야한다고 들었습니다. #포함 진술 .cpp 파일이지만 운이 좋지 않습니다. 그런 것을 시도하면 추가 오류가 발생합니다.
error: forward declaration of 'struct ClassName'
어쩌면 나는 단지 올바른 장소에서 일을하지 않는다고 생각합니다. 누군가이 코드를 컴파일하는 방법을 보여줄 수 있습니까? 매우 감사합니다!
편집 : 이것은 단지 실제 코드의 추상화 된 버전이라고 지적하고 싶습니다. 나는 언급이 없다는 것을 알고있다 케이 안에 ㅏ 또는 비 안에 제이, 그러나 실제 코드에는 실제 코드가 있으며 완전히 필요하다고 생각합니다. 아마도 실제 클래스에 대한 간단한 설명을한다면 누군가가 내 코드를 재구성하거나 수정하는 데 도움이 될 수 있습니다.
수업 ㅏ 그래프의 노드에 대한 인터페이스 역할을하는 추상 노드 클래스입니다. 수업 비 여러 가지 다른 구현 중 하나입니다. ㅏ. 같은 방식으로 클래스 제이 추상 방문자 수업입니다 케이 해당 구현입니다. 다음은 조금 더 문맥이있는 코드입니다.
아 (추상 노드)
#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 {};
main.cpp
#include "A.h"
int main()
{
return 0;
}
(세부 사항을 추가했을 때)가 사라지는 추가 오류를 만들기 위해 선언문을 추가해야했습니다. 그들 중 일부는 필요하거나 정확하지 않을 수 있습니다.
해결책
원형 포함은 작동하지 않습니다.
내포물을 엄격한 최소로 유지하십시오. 그렇게한다면, 당신은 모두 괜찮을 것이거나 디자인에서 문제를 발견하게 될 것입니다. 귀하의 경우, 나는 당신의 디자인에 아무런 문제가 없습니다.
클래스 k를 정의 할 때 B는 B 형의 객체에 대한 포인터 만 사용하고 있습니다. B를 정의 할 필요는 없습니다 ( "헤더 파일 포함"에서와 같이). 따라서 귀하의 경우, "BH"에 포함 된 "BH"에 대한 포함을 "클래스 B"로 대체했습니다. 충분하다. (클래스 j도 마찬가지)
다른 팁
헤더 포함은 원형입니다. A -> k-> j-> b-> A. 전방 선언을 사용하는 것은 그러한 복잡성을 피하는 가장 간단한 방법이지만, 선언 된 클래스가 참조 또는 포인터 만 포함되는 클래스에만 사용하는 경우에만 가능합니다. 예를 들어 J 및 A에서 각각 상속하기 때문에 KH 또는 BH에서 전방 선언을 사용할 수 없습니다. 그러나 교체 할 수 있습니다 #include "K.h"
아와 함께 class K;
실제로 사용하는 방식에 따라 다릅니다 K
안에 A
.
혼란에 대해 이야기하십시오.
이 구체적인 예에서는 제거하십시오
#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
)
주요 문제는 헤더 파일에 원형 방식으로 서로를 포함한다는 것입니다. A는 B를 포함하는 k를 포함하여 B를 포함합니다. 여기에는 A가 포함됩니다. 디자인 드로잉 보드로 돌아가서 종속성 중 일부를 자르 거나이 원형 의존성이 발생하지 않도록 클래스를 완전히 재구성해야합니다.
문제는 헤더 파일이 서로 주기적으로 의존한다는 것입니다. 포함하지 마십시오 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
}