6

非常に基本的な式パーサーを作成しましたが、拡張可能にして、ユーザー定義の式タイプを解析できるようにしたいと考えています。たとえば、解析中に文字 に遭遇した場合、<この文字で始まる式の解析に使用されるクラスのインスタンスを作成したいとします。

2 つの質問があります。

  1. 文字を静的メソッド ポインターに関連付けるにはどうすればよいですか?

    クラス コンストラクターへのポインターを取得できないため、クラスの新しいインスタンスを返す静的メソッドを使用したいと考えています。次の構文はおそらく間違っていますが、それが考え方です。

    typedef static IValue * (*returnPtrIValue)();
    map<char, returnPtrIValue> ...
    
  2. クラス A があり、クラス B がクラス A を拡張すると仮定すると、B は A であるため、B へのポインター/参照を返す関数へのポインターを使用して、A へのポインター/参照を返す関数へのポインターを初期化できますか?

    たとえば、次のことができますか。

    typedef A * (*returnPtrA)();
    B * func() { ... }
    returnPtrA foo = func;
    
4

5 に答える 5

3

1: 次staticのように typedef から削除します。

typedef IValue * (*returnPtrIValue)();

静的メンバー関数へのポインターは、次のように、その型の変数に割り当てる (またはマップに入れる) ことができます。

returnPtrIValue fun = &SomeClass::somestaticfun;

これはあなたが求めているものですか?

2: 一般的に言えば - いいえ。少なくともタイプセーフな方法ではありません。共分散は、C++ ではそのようには機能しません。

本当にこれをやりたい場合は、これをreinterpret_cast行うか、共用体を使っていくつかのハッカーを行うことができますが、これはコンパイラに依存する可能性があり、お勧めしません (とにかくこれが必要な場合は、いくつかのヒントを与えることができます)。

更新: これは、C++ の (メンバー) 関数ポインターを使用して C++ でデリゲートを実装する方法を説明する、非常に優れた記事です。質問をかなり深く掘り下げており、前半はC ++の(メンバー)関数ポインターとそれらの操作方法のかなり良い参照/説明であることがわかりました。それらが C++ でどのように機能するかを理解することに興味がある場合は、チェックすることをお勧めします。

于 2013-05-26T11:46:21.303 に答える
2

1) typedefから削除するだけstaticです。「静的メソッド」は単純な関数のようなものです(クラスのスコープ内でのみ宣言されます)。

2)それは正当に思えましたが、残念ながらコンパイルエラーが発生しました:

error: invalid conversion from 'B* (*)()' to 'A* (*)()'

関数ポインターは共変の戻り値の型をサポートしていないようです...

于 2013-05-26T11:45:15.703 に答える
1

C++11 を使用している場合は、次のように試すことができます。

#include <map>
#include <functional>
...
std::map<char, std::function<parser*()>> m;
m['a'] = []{return new parser_for_a;};

この方法では、静的メソッドを持つ必要はありません。

于 2013-05-26T11:55:10.930 に答える
0

このコードは、正確でなくても、質問に答える必要があります。実際、virtual呼び出しを使用して問題のいくつかを解決しました (注意: パフォーマンスの問題)。

#include <iostream>
#include <map>


struct parse_result {
    // something here
};

class parser {
public:
    virtual parse_result parse() = 0;
};

class parser1 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser1::parse()" << std::endl;
        return parse_result();
    }
};

class parser2 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser2::parse()" << std::endl;
        return parse_result();
    }
};

static parser1* make_parser1() {
    return new parser1();
}

static parser2* make_parser2() {
    return new parser2();
}

typedef parser* (*parser_factory_method)();


int main() {

    std::map<char, parser_factory_method> parsers;
    parsers.insert(std::make_pair('1', (parser_factory_method) make_parser1));
    parsers.insert(std::make_pair('2', (parser_factory_method) make_parser2));

    for (auto entry : parsers) {
        std::cout << "Calling parser for " << entry.first << std::endl;
        parser_factory_method pfm = entry.second;
        parser* p = pfm();
        p->parse(); // parse_result is ignored here, but can be used as needed
        delete p;
    }

    return 0;

}

このパーサーの設計は好きではないことに注意してください。何らかの方法で Java リフレクションを模倣しており、パフォーマンスの問題が発生する運命にあります。洗練できるかどうかを確認します。

于 2013-05-26T11:46:01.950 に答える
0

このスレッドは、私が望んでいたことをするのに役立ちました:クラスオブジェクトを動的に作成する方法は? ご回答ありがとうございます。

于 2013-05-26T14:09:03.447 に答える