0

私は問題に直面した大きなプロジェクトを持っています。それはすぐに次のように定式化することができます:

一時的に作成され、一部のデータを処理および変更するために使用されるクラスがありました(これを「ワーカー」と呼びましょう)。これで、2つのワーカーと2つの対応するデータ形式ができました。データ配列には混合データを含めることができますが、プログラムで作成してデータ処理に使用するワーカークラスを自動的に決定するにはどうすればよいですか?これを最善の方法で作成するにはどうすればよいですか?

この問題を説明するために、私のプロジェクトに類似した小さなサンプルプログラムを作成しました。

#include <iostream>
#include <vector>
using namespace std;

const int NInputs = 10;



struct TOutput {
  int i;
};

class TProcess {
  public:
  TProcess( const vector<TInput>& i ){ fInput = i; }

  void Run();

  void GetOutput( TOutput& o ) { o = fOutput; }
  private:
  vector<TInput> fInput;
  TOutput fOutput;
};

#if 0
struct TInput {
  int i;
};
class TWorker{
 public:
  void Init( int i ) { fResult = i; }
  void Add( int i ) { fResult += i; }
  int  Result() { return fResult; } 
 private:
  int fResult;
};
#else
struct TInput {
  int i;
};
class TWorker {
 public:
  void Init( int i ) { fResult = i; }
  void Add( int i ) { fResult ^= i; }
  int  Result() { return fResult; } 
 private:
  int fResult;
};
#endif

void TProcess::Run() {
  TWorker worker;
  worker.Init(0);
  for( int i = 0; i < fInput.size(); ++i )
    worker.Add(fInput[i].i);

  fOutput.i = worker.Result();
}

int main()  {
  vector<TInput> input(NInputs);

  for  ( int i = 0; i < NInputs; i++ ) {
    input[i].i = i;
  }

  TProcess proc(input);
  proc.Run();

  TOutput output;
  proc.GetOutput(output);

  cout << output.i << endl;
}

例は非常に単純ですが、それはそれを1つの関数に変換することが単純に可能であることを意味するわけではありません---それは大きなプロジェクトに対応します。したがって、次のことはできません。

  • すでに存在するクラスまたは関数を削除します(ただし、それらを変更して新しいものを作成することは可能です)
  • ワーカーを静的にするか、ワーカーのコピーを1つだけ作成します(各ワーカーは、多くの複雑な関数やループで一時的なものです)

したがって、これが次のようになるように変更する方法は次のとおりです。

 // TODO: TProcess declaration

struct TInput1 {
  int i;
};
class TWorker1{
 public:
  void Init( TInput1 i ) { fResult = i; }
  void Add( TInput1 i ) { fResult += i.i; }
  int  Result() { return fResult; } 
 private:
  int fResult;
};
#else
struct TInput2 {
  int i;
};
class TWorker2 {
 public:
  void Init( TInput2 i ) { fResult = i.i; }
  void Add( TInput2 i ) { fResult ^= i.i; }
  int  Result() { return fResult; } 
 private:
  int fResult;
};

void TProcess::Run() { 
  for( int i = 0; i < fInput.size(); ++i ) {
    // TODO: choose and create a worker
    worker.Add(fInput[i].i);
    // TODO: get and save result
  }

  fOutput.i = worker.Result();
}

int main()  {
  vector<TInputBase> input(NInputs);

  // TODO: fill input

  TProcess proc(input);
  proc.Run();

  TOutput output;
  proc.GetOutput(output);

  cout << output.i << endl;
}

私の最初のアイデアは、基本的なクラス関数とテンプレート関数を使用することでしたが、テンプレート仮想関数はありません...

4

1 に答える 1

1

2 番目の例の宣言は正しい考えvector<TInputBase>です。すべての入力に共通の基本クラスが必要であり、同様にすべてのワーカーにも必要です。

class TInput {
}

class TInput1 : public TInput { ... }
class TInput2 : public TInput { ... }

class TWorker {
public:
  void Init(TInput *input) = 0;
  void Add(TInput *input) = 0;
  int Result() = 0;
}

class TWorker1 : public TWorker { ... }
class TWorker2 : public TWorker { ... }

ただし、これはすべてのワーカーがTInput *を入力としてのみ受け取ることができることを意味し、各ワーカー クラス内で正しい入力クラスにキャストする必要があることに注意してください。

特定の入力に使用するワーカー クラスを決定する最も簡単な方法は、入力自体に問い合わせることです。適切な種類のワーカーを作成する入力クラスに仮想関数を含めることができます。

class TInput {
  virtual TWorker *createWorker() = 0;
}

class TInput1 : public TInput {
  TWorker *createWorker() {
    return new TWorker1();
  }
}

class TInput2 : public TInput {
  TWorker *createWorker() {
    return new TWorker2();
  }
}

何らかの理由でこれが不可能な場合は、 を使用typeidして入力のタイプを判別し、対応するワーカー インスタンスを作成できます。

于 2012-08-20T05:25:12.557 に答える