注意してください: これらは、一般的なジレンマを表すコード スニペットです。完全なコードには、「ガードを含める」/ #pragma once / whathaveyou が含まれています。
私は AST をトラバースするためのビジター パターンを実装しており、次の問題を解決する C++ の方法を考えています。
ベース AST ノード クラス宣言を持つ AST.h があります。
class Node
{
public:
virtual void accept(Visitor* v) {v->visit(this);}
};
宣言、式などのすべての具象ノード サブクラスとともに.
そして、次の行に沿って、ビジター インターフェイスを宣言する ASTVisitor.h があります。
class Visitor
{
public:
Visitor() {}
virtual ~Visitor() {}
virtual void visit(StringElement* e) {}
virtual void visit(RealElement* e) {}
virtual void visit(IntegerElement* e) {}
...
問題は、AST.h が ASTVisitor.h を必要とするため、Accept メソッドは Visitor オブジェクトに Visit メソッドがあることを認識します。つまり、 Visitor と visit() の両方が に対して宣言されるようになりvirtual void accept(Visitor* v) {v->visit(this);}
ます。しかし同時に、Node の具象サブクラスがすべて存在することを Visitor クラスが認識できるように、ASTVisitor.h には AST.h が必要です。つまり、たとえば、 StringElement が署名に対して宣言されているようにvirtual void visit(StringElement* e)
しかし、ASTVisitor.h に ASTVisitor.h を含め、ASTVisitor.h に AST.h を含めると、Visitor クラスが Node クラスから「認識」されないため、accept のパラメーターの型として有効ではなくなります。また、class Visitor;
AST.h のように前方宣言を行うと、メソッド シグネチャの型の問題のみが解決されv->visit(this)
ますが、前方宣言は Visitor クラスのメソッドについて何も述べていないため、メソッド内は依然として無効です。
では、これを解決する C++ の方法は何ですか?