编码数学类/函数时的最佳实践是什么?

时间:2010-05-18 08:13:40

标签: c++ math

介绍性说明:我自愿选择了一个广泛的主题。你知道关于学习捕鱼的报价,就是这样。我不需要回答我的问题,我需要一个解释和建议。我知道你们擅长这个;)


大家好,

我目前正在将一些算法应用到现有程序中。长话短说,我创建了一个新类“Adder”。 Adder 是另一个类的成员,表示实际执行微积分的物理对象,它使用其参数调用adder.calc()(仅用于进行数学运算的对象列表)。

要做这些数学,我需要一些参数,这些参数在类之外不存在(但可以 set ,见下文)。它们既不是配置参数也不是其他类的成员。这些参数是D1和D2,距离以及三个固定大小的数组:alpha,beta,delta。

我知道你们中的一些人阅读代码比阅读文本更舒服,所以在这里:

class Adder
{
public:

  Adder();
  virtual Adder::~Adder();

void set( float d1, float d2 );
  void set( float d1, float d2, int alpha[N_MAX], int beta[N_MAX], int delta[N_MAX] );

  // Snipped prototypes
  float calc( List& ... );
  // ...

  inline float get_d1() { return d1_ ;};
  inline float get_d2() { return d2_ ;};

private:

  float d1_;
  float d2_;

  int alpha_[N_MAX]; // A #define N_MAX is done elsewhere
  int beta_[N_MAX]; 
  int delta_[N_MAX]; 
};

由于此对象用作另一个类的成员,因此它在* .h:

中声明
private:
  Adder adder_;

通过这样做,我无法直接在构造函数中初始化数组(alpha / beta / delta)(int T [3] = {1,2,3};),而不必遍历三个数组。我想把它们放在 static const 中,但我不认为这是解决这些问题的正确方法。

我的第二个猜测是使用构造函数初始化数组

Adder::Adder()
{
    int alpha[N_MAX] = { 0, -60, -120, 180, 120,  60 };
    int beta[N_MAX] = { 0,   0,    0,   0,   0,   0 };
    int delta[N_MAX]  = { 0,   0,  180, 180, 180,   0 };

    set( 2.5, 0, alpha, beta, delta );
}

void Adder::set( float d1, float d2 ) {
    if (d1 > 0)
        d1_ = d1;

    if (d2 > 0)
        d2_ = d2;
}

void Adder::set( float d1, float d2, int alpha[N_MAX], int beta[N_MAX], int delta[N_MAX] ) {
    set( d1, d2 );

    for (int i = 0; i < N_MAX; ++i) {
        alpha_[i] = alpha[i];
        beta_[i] = beta[i];
        delta_[i] = delta[i];
    }
}

我的问题是:使用另一个函数 - init() - 会初始化数组会更好吗?或者有更好的方法吗?

我的奖金问题是:您是否看到了一些错误或不良做法?

4 个答案:

答案 0 :(得分:5)

你选择了一个非常广泛的主题,所以这是一个更广泛的答案。

  • 注意周围环境

我经常看到代码与代码库中的其他地方做同样的事情。确保您的队友或前任尚未解决您尝试解决的问题。

  • 尽量不要重新发明轮子

我前一点的延伸。

虽然每个人都应该编写链表或字符串类作为练习,但是没有必要为生产代码编写一个。您可以访问MFC,OWL,STL,Boost等等。如果已经发明了车轮,请使用它并继续编写解决方案以解决真正的问题!

  • 考虑一下如何测试代码

Test Driven Development (TDD)是确保您的代码既可测试又经过测试的一种方式(但不是唯一的方法)。如果您考虑从一开始就测试代码,那么测试将非常容易。 然后测试一下!

  • 编写SOLID代码

The Wikipedia page对此的解释远远超出我的预测。

  • 确保您的代码可读

有意义的标识符只是一个开始。不必要的注释也会降低可读性,因为长函数,具有长参数列表的函数(例如第二个setter)等等。如果您有coding standards,请坚持使用。

  • 使用const更多

我对C ++的主要抱怨是默认情况下不是const!在您的示例中,您的getter应声明为const,并且您的setter应将其参数传递为const(以及const - 数组的引用。)

  • 确保您的代码可维护

单元测试(如上所述)将确保下一个更改代码的人不会破坏您的实现。

  • 确保您的资料库可用

如果您关注Principle of least astonishment并使用单元测试来记录您的库,那么使用它的程序员可以减少问题。

前一点的延伸。尽你所能减少代码重复。今天我目睹了一个必须在十五个不同的地方执行的错误修复(并且只在其中的十三个中执行)。

答案 1 :(得分:4)

创建对象时,我建议始终为用户提供完整的对象,并正确初始化所有成员。 Init方法无法做到这一点,为常见错误腾出空间,无法在两阶段初始化对象中调用初始化函数。

要防止这种情况,请将构造函数设为私有并使用构建器函数或工厂,它们可以访问init方法,或者使init成为私有的,并在构造函数中使用它。最后一条建议通常与在构造函数中进行初始化相同,但它允许多个构造函数使用相同的初始化操作。

答案 2 :(得分:1)

好。 我会:

  1. 将数组设置为已知状态 使用memset清除所有值 0(或其他一些值) 构造函数在使用之前。
  2. 更改构造函数以允许     传递可以的数组指针     用于初始化数组     其他一些价值观。
  3. 保留套装     你必须改变的功能     数组中的值和     你正在使用的东西。

答案 3 :(得分:1)

  1. 不要使用虚拟功能,除非您的设计确实需要它们。
  2. 在主要用于执行一个函数的类中,该函数规范地命名为operator()。即你打电话给你的是adder_(params),而不是adder_.calc(params)
  3. 如果要初始化三个数组,使用三个for循环会更有效。 (缓存友好)