Как обобщенно представить параметр с помощью ОО? - PullRequest
2 голосов
/ 04 января 2011

В C ++ мне нужно реализовать несколько алгоритмов, которые представляют разные способы вычисления одного и того же.

Я думал об использовании интерфейса для представления другого алгоритма.

class AlgorithmInterface
{
  public:
    virtual double ComputeSomething(void* parameter) = 0;
}

class AlgorithmImplementation1: public AlgorithmInterface
{
  public:
    virtual double ComputeSomething(void* parameter) { /* implementation */}
}

class AlgorithmImplementation2: public AlgorithmInterface
{
  public:
    virtual double ComputeSomething(void* parameter) { /* implementation */}
}

Однако параметр (void * в предыдущем примере) для каждого из них различен, как я могу представить их в общем виде?

Я использовал пустоту * для примера, просто потому, что я не знаю, как это представить. Пожалуйста, скажите мне, как я должен сделать это: я должен сделать эквивалентное наследование для параметров и привести их? (мне это кажется некрасивым)

Ответы [ 5 ]

9 голосов
/ 04 января 2011

Вы можете передать параметры в конструкторе.
Дополнительно сделайте виртуальный член приватным и сделайте объект функтором:

class AlgorithmInterface
{
  public:
     double operator()() {return this->ComputeSomething();}
  private:
    virtual double ComputeSomething() = 0;
}

class AlgorithmImplementation1: public AlgorithmInterface
{
    virtual double ComputeSomething() { /* implementation */}
    public:
        AlgorithmImplementation1(Parameter 1);
}

class AlgorithmImplementation2: public AlgorithmInterface
{
    virtual double ComputeSomething() { /* implementation */}
    public:
        AlgorithmImplementation2(Item a1,Item a2);
}

int main()
{
    AlgorithmImplementation2   job(Item(12), Iterm(13));

    double result = job(); // execute;
}
3 голосов
/ 04 января 2011

(основываясь на моем понимании вашего вопроса) Если вычисления не меняются, и меняются только типы параметров, вы можете использовать templates ..

1 голос
/ 04 января 2011

Еще одна возможность - передать поток параметров в алгоритмы. Алгоритм может принимать ссылку на ParameterStream.

Производные алгоритмы будут затем извлекать соответствующие типы (количество) параметров из потока соответственно. Поток реализует безопасное извлечение (десериализацию) параметров типа, а также может реализовать (при желании) управление версиями.

Эта возможность ИМХО будет иметь преимущество в том, что вы можете сохранить интерфейс неизменным, даже если в будущем для разных алгоритмов потребуется другое количество параметров.

Таким образом, в основном вы отправляете параметр, который содержит сериализованную форму нужных вам параметров, и вы десериализуете / проверяете их по мере необходимости в реализации алгоритма.

Как уже упоминалось в предыдущих постерах, шаблоны также могут быть полезны, если во время компиляции все четко.

1 голос
/ 04 января 2011

Либо вы используете классический ОО (во время выполнения) полиморфизм, в этом случае параметр должен быть указателем / ссылкой базового класса, к которому могут передаваться объекты производного класса, либо вы переключаетесь на шаблоны и полиморфизм во время компиляции,как это делает STL, и передают алгоритм и параметр как экземпляр параметра шаблона.

С шаблонами ваш код может выглядеть так:

class AlgorithmImplementation1
{
  public:
    virtual double ComputeSomething(Param1* parameter) const
    { /* implementation */}
}

class AlgorithmImplementation1
{
  public:
    virtual double ComputeSomething(Param2* parameter) const
    { /* implementation */}
}

template< typename Algorithm >
void use_algorithm(const Algorithm& algorithm)
{
  // ...
  // get_parameter() _must_ return whatever the algorithm takes
  double d = algorithm( get_parameter() );
  // ...
}

Param1 get_parameter();

void f()
{
  use_algorithm( AlgorithmImplementation1() );
}
0 голосов
/ 04 января 2011

Вам действительно нужно наследство? Если вы это сделаете, то шаблонирование функции не будет опцией (т. Е. У вас не может быть шаблона виртуальной функции - по крайней мере, в текущем стандарте), и решение Мартина работает. Если вам не нужно наследование, тогда должно хватить приведенного ниже

class AlgorithmImplementation1
{
  public:
    template <typename ParamType>
      double ComputeSomething(ParamType const& parameter) { /* implementation */}
}

class AlgorithmImplementation2
{
  public:
    template <typename ParamType>
      double ComputeSomething(ParamType const& parameter) { /* implementation */}
}

Это, конечно, зависит от того, как вы планируете использовать parameter, вам может быть лучше использовать перегрузку (например, обрабатывать int иначе, чем string), если ваш parameter имеет согласованный интерфейс, тогда Шаблон функции будет достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...