根据C ++

时间:2017-09-14 17:41:09

标签: c++ constructor

原始代码太复杂,所以我将问题抽象如下:

class A {
  public:
    A (int p): _p{p} {}

    float computeA (float a) {
      if (_p == 0)
        return 0.1f + expf(a);
      else if (_p == 1)
        return 0.2f + sqrtf(a);
      else if (_p == 2)
        return 0.3f + sinf(a);
      return 0.4f +cosf(a);
    }

    float accumulate() {
      ...
      for(...) {
        int temp = computeA();
        // other calculations...
      }
      ...
    }

    ...

  private:
    const int _p;
};

_p A 中的常量成员,并且只能是0,1,2或3. computeA()中的计算取决于 _p 的值。由于 _p 在创建 A 时已经知道,我想知道是否有一种正确的方法来避免代码中的“if”条件。

多态性对于每个子类只更改一行代码是不实际的(或者是?)( A 有十几个成员函数,只有 computeA()有所作为)。另一个问题可能是性能,因为简单的 computeA()经常在重 accumulate()的大循环中调用。多态函数调用的开销会变得不可接受吗?

谢谢,

2 个答案:

答案 0 :(得分:1)

  

对于每个子类只更改一行代码,多态性是不实际的(或者是?)...

当然可以。基本类型具有所有相同的代码,但computeA()除外,它变为纯虚拟:

float computeA(float) = 0;

然后每个基地只覆盖那一个方法。

请注意,如果间接函数调用开销是可接受的(请参阅下一节),那么您可以让构造函数使用std::function<float(float)>并让调用者通过expfsqrtf,等等。这样你就不需要孩子课了,班级消费者不仅限于四种功能 - 也不仅限于功能(算子变得可行)。

  

多态函数调用的开销是否会变得不可接受?

这是一个很好的问题,您可以通过对这两个选项进行基准测试来解决您的特定用例

如果您坚持使用条件方法,可以提出一些建议:

  • _p应该更适合class enum类型,这样您就不会在代码中出现幻数。
  • 考虑使用switch代替if。因为它通常被实现为计算goto,所以它有可能稍快一些。 (然而,智能编译器可能会将您的多个条件优化为单个计算goto。)

答案 1 :(得分:1)

您可以使用简单的函数指针:

float compute0(float a) { return 0.1f + expf(a); }
float compute1(float a) { return 0.2f + sqrtf(a); }
float compute2(float a) { return 0.3f + sinf(a); }
float compute3(float a) { return 0.4f + cosf(a); }

class A {
  public:
    typedef float (*functype)(float);

    A (int p) {
      switch (p) {
        case 0:  _func = &compute0; break;
        case 1:  _func = &compute1; break;
        case 2:  _func = &compute2; break;
        default: _func = &compute3; break;
    }

    float computeA (float a) {
      return _func(a);
    }

    ...

  private:
    functype _func;
};

或者,如果您想要使用它,可以使用lambdas代替:

class A {
  public:
    A (int p) {
      switch (p) {
        case 0:  _func = [](float a) { return 0.1f + std::exp(a); }; break;
        case 1:  _func = [](float a) { return 0.2f + std::sqrt(a); }; break;
        case 2:  _func = [](float a) { return 0.3f + std::sin(a); }; break;
        default: _func = [](float a) { return 0.4f + std::cos(a); }; break;
    }

    float computeA (float a) {
      return _func(a);
    }

    ...

  private:
    std::function<float(float)> _func;
};

或者,让创建A对象的代码决定使用以下内容计算的值和函数:

class A {
  public:
    typedef float (*functype)(float);

    A (float value, functype func) :
      _value(value), _func(func)
    }

    float computeA (float a) {
      return _value + _func(a);
    }

    ...

  private:
    const float _value;
    const functype _func;
};

A a1(0.1f, &expf);
A a2(0.2f, &sqrtf);
A a3(0.3f, &sinf);
A a4(0.4f, &cosf);

或者:

class A {
  public:
    using functype = std::function<float(float)>;

    A (float value, functype func) :
      _value(value), _func(func)
    }

    float computeA (float a) {
      return _value + _func(a);
    }

    ...

  private:
    const float _value;
    const functype _func;
};

A a1(0.1f, std::exp);
A a2(0.2f, std::sqrt);
A a3(0.3f, std::sin);
A a4(0.4f, std::cos);

或者,使用多态,让调用者决定使用哪个子类(甚至创建自己的子类进行自定义计算):

class A {
  public:
    A () {}

    virtual float computeA (float a) = 0;

    ...
};

class A_exp : public A {
  public:
    float computeA (float a) override { return 0.1f + std::exp(a); }
};

class A_sqrt : public A {
  public:
    float computeA (float a) override { return 0.2f + std::sqrt(a); }
};

class A_sin : public A {
  public:
    float computeA (float a) override { return 0.3f + std::sin(a); }
};

class A_cos : public A {
  public:
    float computeA (float a) override { return 0.4f + std::cos(a); }
};

A_exp a1;
A_sqrt a2;
A_sin a3;
A_cos a4;