1

大学の宿題で、関数 (またはコマンド) に基づく言語のインタープリターを C++ で作成する必要があります。インタープリターは、入力ファイルを読み取り、単語 (文字列) を抽出し、コマンドを生成して実行する必要があります。Commandすべてのコマンドは、 という仮想メソッドを持つ共通のスーパークラス ( など) から継承するクラスexecuteです。入力ファイルから読み取られた単語ごとに、コマンドが作成され、vector<Command>.

そのため、キーがコマンド (文字列) の名前であり、値が特定のクラスを作成できるようにする (または特定のクラスのコンストラクターにアクセスできるようにする) ある種のオブジェクトであるハッシュテーブルを使用することを考えています。 )、一連の if-else-if を使用する代わりに、各単語のクラスを簡単に作成できます。

今のところ、新しいオブジェクトを返すというCommandGenerator仮想メソッドを持つクラスを作成する予定です。私のコマンド ハッシュ テーブルの値は、クラスのオブジェクトになります。そのため、すべてのコマンドの他の多くのサブクラスを派生させて、 から派生した特定の新しいオブジェクトを返します。generateCommandCommandGeneratorCommand

しかし、そのようなものはすでに存在しますか?または、それを行うためのよりエレガントな方法はありますか? それを表すためにクラスから抽出できるオブジェクトの種類はありますか?

4

2 に答える 2

1

あなたが持っている基本的な問題は次のとおりです。あなたは文字列としてクラスの名前を持っていて、その名前でクラスを作成したいと思っています。あなたが言ったように、あなたはどういうわけか手動でこの翻訳をしなければなりません。これは、ファクトリパターンを使用した名前によるクラスのインスタンス化、より優れたC ++クラスファクトリの検索など、ここで何度か説明されています。ここで追加するのは、stringize-operatorがあるため、古き良きマクロを使用することだけです。例えば:

#include <stdio.h>
#define CREATEOBJ(clss,command) if (strcmp (#clss, command)==0) return new clss;
class Base {
public:
  virtual const char *name()=0;
};
class A : public Base {
public:
  const char *name() {return "I am an A";}
};
class B : public Base {
public:
  const char *name() {return "I am an B";}
};
Base *makeInstance (const char *nm) {
  CREATEOBJ(A,nm);
  CREATEOBJ(B,nm);
}
int main () {
  printf ("%s\n", makeInstance ("A")->name());
  printf ("%s\n", makeInstance ("B")->name());
}

もちろん、文字列と関数ポインタまたはジェネレータクラスポインタを含むハッシュテーブルを使用することで、より良いものにすることができますが、考え方は同じです。新しいクラスを追加するには、CREATEOBJ-thingyをもう1つ追加するだけです。

于 2012-12-15T17:23:29.347 に答える
1

各コマンドが のサブクラスである場合、 を使用して、各サブクラスのインスタンスへのポインターをプッシュCommandしないのはなぜですか? std::vector<Command*>次に、ベクトルを反復処理して、仮想execute関数を呼び出すことができます。

ベクトルにクラスを配置することについて得られる最も近いものはboost::fusion::vector. ただし、実行時に入力することはできません。特定のケースでは使用できません。


C++11 を使用できると仮定します。コマンドを単なるexecute関数として定義できる場合は、次のようなことができます。

map<string, function<void()>> cmds = {
    make_pair("print1", [](){
        cout << "1" << end;
    }),
    make_pair("print2", [](){
        cout << "2" << end;
    }),
    make_pair("print3", [](){
        cout << "3" << end;
    })
};

そして、次のコマンドをベクトルに配置します。

vector<function<void()>> list;
list.push_back(cmds["print1"]);
list.push_back(cmds["print1"]);
list.push_back(cmds["print2"]);

次に、ループで実行します。

for (function<void()>& cmd : list)
    cmd();

これは112画面に出力されます。ただし、速度を重視する場合は、代わりに多くの ifs を実行してください。

于 2012-12-15T17:12:55.680 に答える