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() {}
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. 。場合によっては、前方宣言を使用してから、 #含む ステートメントへの .cpp ファイルを作成しましたが、うまくいきません。そのようなことを試みると、追加のエラーが表示されます。
error: forward declaration of 'struct ClassName'
おそらく私は正しい場所で物事を行っていないだけだと思います。誰かこのコードをコンパイルする方法を教えてくれませんか?どうもありがとうございます!
編集:これは実際のコードを抽象化したものにすぎないことを指摘しておきたいと思います。言及がないことは承知しています K で あ または B で J, 、しかし実際のコードにはそれらがあり、それらは完全に必要であると感じます。おそらく、実際のクラスについて簡単に説明すれば、誰かがコードの再構築や修正を手伝ってくれるでしょう。
クラス あ は、グラフ内のノードのインターフェイスとして機能する抽象ノード クラスです。クラス B これは、さまざまな実装のうちの 1 つです。 あ. 。同様に、クラス 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() {}
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;
}
(詳細を追加したときに) 表示されたいくつかの追加エラーを解消するには、いくつかの前方宣言を追加する必要がありました。それらの中には、必要でないものや正しくないものもあります。
解決
円形介在物は動作しません。
厳しい最小限に介在物を保つようにしてください。あなたがそれを行う場合は、どちらか完全に大丈夫ですか、あなたのデザインの問題を発見するでしょう。あなたのケースでは、私はあなたのデザインと間違って何も表示されません。
クラスKを定義する場合、、あなただけ前方宣言が細かい(のみ宣言する、(「ヘッダファイルを含む」のように)定義するBを必要としないタイプBのオブジェクトへのポインタを使用しています)。だから、あなたの場合には、含有を除去することによって置き換えられ、「B.h」ヘッダに「クラスBを、」十分なものです。 (同じクラスJのために行く)
他のヒント
あなたのヘッダ介在物は円形です。 - > K - > J - > B - 前方宣言を使用> A.は、このような複雑さを回避するための最も簡単な方法ですが、クラスのみ含まれているクラスへの参照やポインタを使用して宣言されたときにのみ可能です。彼らはそれぞれJとAから継承するので、あなたは、例えば、K.hまたはB.hで宣言を前方に使用することはできません。しかし、あなたはどのようにあなたが実際に#include "K.h"
でclass K;
を使用しているに応じて、K
とA.hにA
を置き換えることができるかもしれません。
混乱についての講演ます。
この具体例では、削除
#include "B.h"
ファイルJ.h
からそれはそこに必要としない「S以来。それでも解決しない場合は、我々は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
を含む)
主な問題は、あなたのヘッダファイルが環状にお互いが含まれていることです。 Aは再び...あなたはこの問題が発生した状況を要求することはありません含まれてBを含んでJを含んでKを含んでいます。あなたは設計図面ボードに戻って、いずれかの依存関係の一部をカットするか、この循環依存が起こらないように完全にあなたのクラスを再編成する必要があります。
問題は、ヘッダー ファイルが相互に周期的に依存していることです。含めないでください K.h
で A.h
そして B.h
で J.h
. 。そこにはそれらは必要ありません。
あなたの編集に関して:これはオブジェクトが対話するための最良の方法ではありません。デザインを再考してください。誰が電話するか node.accept(visitor)
?電話できませんか visitor(node)
直接?
また、グラフ ライブラリを設計しようとしている場合は、以下を参照してください。 ブーストグラフ 図書館。
とはいえ、使用するのはポインターのみであるため、 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
}