【问题标题】:C++ Using inheritance to tweak an algorithmC++ 使用继承来调整算法
【发布时间】:2013-11-21 17:04:30
【问题描述】:

由于 Dijkstra 的算法和 Prim 的算法非常相似,我想创建一个基本算法类(我会称之为“Greedy”之类的),然后我想从 Greedy 继承并根据类。

我认为归结为这一点。我想重用算法的大部分,但要调整一两个操作。

class BaseAlg
{
public:
    BaseAlg(std::vector<int> data)  //constructor sums a vector and stores result
    {
        int accum = 0;
        for (unsigned int i = 0; i < data.size(); ++i)
            accum += data[i];
        result = accum;
    }

protected:
    int result;
};

class Alg1  //A second, similar algorithm
{
public:
    Alg1(std::vector<int> data)
    {
        //I want to reuse BaseAlg except use *= instead of +=; 
    }
};

因此,一种方法是只拥有一个类(BaseAlg)并将“选择器”值添加到类的构造函数中。我会打开该选择器值并在不同情况下执行 += 或 *= 。我觉得应该有一种方法可以通过继承来实现这种重用,因为在 Greedy 和 Prim 以及 Greedy 和 Dijkstra 之间存在“一种”关系。但我无法完全弄清楚。有什么想法吗?

【问题讨论】:

  • 答案是模板元编程
  • 尝试Modern C++ Design 以获取有关如何以零运行时开销执行此类操作的良好示例。旧的,但最好的 C++ 书籍之一。

标签: c++ algorithm inheritance


【解决方案1】:

您应该使用模板来实现这种“重用但也不是真正的继承”。

例如,在您的情况下,基本上可以归结为:

template<class Op, class Iter, class T> T reduce(const Op & op, Iter begin, Iter end, T init = T()) {
    T accum = init;
    for(Iter i = begin; i != end; ++i)
        accum = Op(accum, *i);
    return accum;
}

你可以这样使用它:

std::vector<int> data; // fill data
int sum = reduce(add<int>, data.begin(), data.end());
int prod = reduce(mul<int>, data.begin(), data.end(), 1);

您需要像这样定义addmult

template<class T> T add(T a, T b) { return a + b; }
template<class T> T mult(T a, T b) { return a * b; }

现在,正如 Jerry Coffin 指出的那样,这一切都是为了说明目的,使用 STL 您可以简单地做到:

#include <functional>
#include <numeric>
int sum = std::accumulate(data.begin(), data.end(), 0, std::plus<int>);

【讨论】:

  • 只是不要直接使用这些,因为您的 reduce 已经在标准库中作为 std::accumulate (并且它也有您的 addmult 的类似物)。跨度>
  • 确实,这是为了说明。不确定它是否可以编译;)
  • 谢谢安托万,太好了
  • 不客气。如果你对设计感兴趣,我支持 anjruu 的推荐“Modern C++ Design”,也可以看看相关的loki 库的代码。
【解决方案2】:

请看Template Method模式

【讨论】:

  • 这本质上是一个仅链接的答案,is not particularly appropriate。您应该提供有关该模式的足够信息,因此不需要在 Wikipedia 或其他地方阅读它。
【解决方案3】:

虽然我会采用 Antoin 的解决方案,但继承也可能有效(但看起来很糟糕):

class BaseAlg {
public:
   BaseAlg () : result (0) {}
   virtual ~BaseAlg () {}

   int Accumulate (std::vector<int>& data) {
      for (unsigned int i = 0; i < data.size(); ++i)
         result = func (accum, data[i]);
      return result;
   }
protected:
   virtual int func (int a, int b) = 0;
private:
   int result;
};

class AlgMult : public BaseAlg {
private:
   virtual int func (int a, int b) {
      return a*b;
   }
};

class AlgSum : public BaseAlg {
private:
   virtual int func (int a, int b) {
      return a+b;
   }
};

【讨论】:

  • 是的,你当然可以这样做,但是你会在一个紧密的循环中对一个非常小的函数进行虚拟调用,这要慢得多。
  • 确实它无论如何都不是有效的,而且总体上很难看,但是 topicstarter 希望它使用继承来实现 :-) 所以,就是这样。在现实生活中,我会使用函数或仿函数自定义的 std::accumulate。
猜你喜欢
  • 1970-01-01
  • 2018-06-20
  • 2016-06-06
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多