原始代码太复杂,所以我将问题抽象如下:
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()的大循环中调用。多态函数调用的开销会变得不可接受吗?
谢谢,
答案 0 :(得分:1)
对于每个子类只更改一行代码,多态性是不实际的(或者是?)...
当然可以。基本类型具有所有相同的代码,但computeA()
除外,它变为纯虚拟:
float computeA(float) = 0;
然后每个基地只覆盖那一个方法。
请注意,如果间接函数调用开销是可接受的(请参阅下一节),那么您可以让构造函数使用std::function<float(float)>
并让调用者通过expf
,sqrtf
,等等。这样你就不需要孩子课了,班级消费者不仅限于四种功能 - 也不仅限于功能(算子变得可行)。
多态函数调用的开销是否会变得不可接受?
这是一个很好的问题,您可以通过对这两个选项进行基准测试来解决您的特定用例。
如果您坚持使用条件方法,可以提出一些建议:
_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;