2

这是我在这里的第一个问题,所以希望这是一个很好的问题(我已经搜索了答案,但还没有找到)。

我有一个用 C++ 编写的基于事件的疾病模型,我正在尝试将其转换为 OOP(部分是出于我自己的学习经验)。基本类别(畜群)存储易感、感染性和抗性动物的数量,以及可能事件发生的速率。

class Herd {  
    private: 
        int S,I,R,N;  
        float birth, death, infection, recovery, movement;  
    public:  
        void calc_birth(void) { birth = r*N*(1.0-N/c); }  
        void calc_infection(void) { infection = N>0 ? beta*S*I/N : 0.0; }  
        // etc.
};  

然后我有vector一群牛群要跟踪。在整个模型中,我需要计算所有群体中每个成员的总和,在事件改变了群体中个体的数量或类别之后(这种情况经常发生)。我已经有 4 个类别和 5 个事件,并且这个模型可以很容易地扩展并且需要更多。

在我的旧程序代码中,我只是为每个成员设置了一个单独的向量,并且很容易创建一个sum()函数来计算结果,但是如果不为每个成员(这是可能的,但我怀疑这是一种特别好的方法)。我可以创建一个静态成员(例如sum_S)来跟踪总数,并在每次发生事件时对其进行更新,但这可能不适用于所有成员,而且我不确定总数是否会慢慢偏离真实值当谈到利率。

有没有办法编写一个sum()函数,它将我想要的成员作为参数,并返回所有牛群中该特定成员的总和?

谢谢!

4

3 回答 3

4

标准库头文件numeric包含函数累计。它并不完全符合您的要求,但很容易适应:

#include <numeric>
#include <vector>
#include <iostream>

struct Foo {
  int member;
};


int main()
{
  std::vector<Foo> v = { {1}, {2}, {3} };

  int sum 
    = std::accumulate(begin(v), end(v), 0,
                      // lambda that sums up
                      [](const int& x, const Foo& y)
                      {return x + y.member;});
  std::cout << sum << std::endl;

  return 0;
}

代码使用initializer_lists和 lambdas。如果您的编译器不支持这些,请使用相应的 C++03 代码(push_back和仿函数)。

于 2013-05-15T09:35:05.623 回答
2

当然,使用指向成员的指针。

float sum_for_member( std::vector< Herd > const &herds, float Herd::*member ) {
    float acc = 0;
    for ( std:vector< Herd >::const_iterator it = herds.begin();
                                             it != herds.end(); ++ it ) {
        acc += (*it).*member;
    }
    return acc;
}

称之为:

float total_recovery = sum_for_member( my_herds, & Herd::recovery );

如果要改用成员函数getRecovery,则参数声明变为float (Herd::*member)(),求和变为acc += ((*it).*member)().


如果您不害怕进一步远离 OO 并进入通用 C++ 风格,您可以使用函数模板并让标准库处理循环:

template< float Herd::*member >
float plus( float lhs, Herd const &rhs )
    { return lhs + rhs.*member; }

vector< Herd > h;
std::accumulate( h.begin(), h.end(), 0., plus< & Herd::recovery > );
于 2013-05-15T09:32:05.087 回答
0

所以这就是我最终得到的(在一个名为 的类State中,它保存了包括 a 在内的模拟状态vector<Herd>):

Class State {
    ...
    template <typename T>
        T sum(T (Herd::*getter)()) {
        T acc = (T) 0.0;
        for (int i=0; i<size; ++i) {
            acc += (herds[i].*getter)();
            }
        return acc;
    ...
}

这适用于个人数量(ints)和事件率(floats),并使用指向成员函数的指针来保留这些值private。在代码中如何调用它的一个示例是:

cout << "total # of S = " << state.sum(&Herd::getS)
    "total # of I = " << state.sum(&Herd::getI)
    "total birth rate = " << state.sum(&Herd::get_birth)
    "total infection rate = " << state.sum(&Herd::get_infection)

等等

非常感谢您的帮助,尤其是对 Potatoswatter。这比我之前繁琐的样板代码要好得多!

于 2013-05-27T14:54:34.690 回答