8

長い紹介、質問は最後にあります:


インターフェイスを作成する基本クラスがあるとします。

class base
{
public:
  virtual ~base();
  virtual void calc( int* variables ) = 0;
}

継承され、機能するいくつかのクラス (ここでは 2 つだけを示します):

class add : public base
{
  const int a, b, c;
public:
  add( int a_, int b_, int c_ ) : a(a_), b(b_), c(c_) {}
  void calc( int* variables ) 
  {
     variables[a] = variables[b] + variables[c];
  }
}

class inc : public base
{
  const int a;
public:
  inc( int a_ ) : a(a_) {}
  void calc( int* variables ) 
  {
     variables[a]++;
  }
}

そして最後に、この構造を使用しているいくつかのコード:

base* task[2];
task[0] = new add( 0, 1, 2 );
task[1] = new inc( 3 );
int data[4];

/* ... */

for( int i = 0; i < 2; i++ )
  task[i]->calc( data );

これまでのところ動作していますが、コンパイル時にタスクを定義しています。これは、入力ファイルを解析してランタイムに変更する必要があります。解析が完了し、in std::stringvariablecommandがオブジェクト タイプ (addまたは などinc) であり、astd::vector<int> paramsがコンストラクターのパラメーターであるとします。

今、私は長いリストを持つことができました

if( command.compare( "add" ) ) 
  task[end] = new add( params[0], params[1], params[2] );
else if( command.compare( "inc" ) ) 
  task[end] = new inc( params[0] );
else /... */

まったく読めなくなることは別として、それは単なる線形検索です。では、なぜ switch ステートメントを文字列に適用できないのですか? std::mapその線形検索を(またはハッシュマップ...)で置き換えたいと思います。

したがって、この長い紹介の後、私は最終的に次の質問にたどり着くことができます。


std::mapオブジェクトへの参照 (?) が、後でその情報から動的にオブジェクトを作成できるような方法で格納されるように、を定義して埋めるにはどうすればよいですか?

したがって、上記のコードを使用して、最終的には次のようになります。

// define and fill
std::map< std::sting, ???? > lookup;
lookup["add"] = add;
lookup["inc"] = inc;

/* ... */

// use:
while( linesInConfigAvailable )
{
  /* ... parse ... */
  switch( params.size() )
  {
    case 1:
      task[end] = new lookup[command]( params[0] );
      break;
    case 3:
      task[end] = new lookup[command]( params[0], params[1], params[2] );
      break;
  }
}

PS: これまでのところ、コードに RTTI は必要ありませんでした。このままでいいのに…。

4

1 に答える 1

13

まあ、あなたはできません。C++ では、クラスはオブジェクトではなく、コンパイル中にコンパイラの作業データ内にのみ存在する抽象的な構造です。

ただし、特定のシグネチャを使用して、いわゆるファクトリー関数を作成することはできます。

class A : public Base
{
public:
     static Base* Create() { return new A; }
};

class B : public Base
{
public:
     static Base* Create() { return new B; }
};

...

編集:「作成」機能がこのように統一されている場合、もちろんテンプレートを作成できます。

次に、関数ポインターをマップに格納できます。

typedef Base* (*FactoryType)();
std::map< std::string, FactoryType >

lookup["A"] = A::Create;
lookup["B"] = B::Create;

それらを適切に呼び出します。

task[end] = lookup[command]();
于 2012-08-19T11:15:36.813 に答える