0

我有一个大项目,我遇到了一个问题,可以简单地表述如下:

我有一个临时创建的类,用于处理和修改一些数据(我们称之为“工人”)。现在我有两个工人和两个相应的数据格式。数据数组可以包含混合数据,如何让我的程序自动决定它应该创建和使用哪个工人类进行数据处理?如何以最好的方式做到这一点?

为了说明这个问题,我编写了与我的项目类似的小示例程序。

#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;
}

这个例子很简单,但这并不意味着它可以简单地转换为一个函数——它对应于大项目。因此,不可能:

  • 删除已经存在的类或函数(但可以修改它们并创建新的)
  • 使工作人员静态或仅创建工作人员的一份副本(每个工作人员在许多复杂的功能和循环中都是临时的)

那么如何修改它,使其变成这样:

 // 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

You've got the right idea with the vector<TInputBase> declaration in your second example -- you need to have a common base class for all inputs, and similarly for all workers:

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 { ... }

Note, however, that this means all workers can only take a TInput * as input and you will need to cast to the correct input class inside each worker class.

The simplest way to decide which worker class to use for a given input is to ask the input itself! You can have a virtual function in the input class that creates the right kind of worker:

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

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

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

If this is not possible for some reason, you can use typeid to determine the type of the input and create a corresponding worker instance.

于 2012-08-20T05:25:12.557 回答