对象数组中特定成员的和

Sum of particular members of an object array

本文关键字:成员 数组 对象      更新时间:2023-10-16

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

我有一个用c++编写的基于事件的疾病模型,我正试图将其转换为面向对象(部分是为了我自己的学习经验)。基本类(畜群)存储易感、感染和耐药动物的数量,以及可能发生的事件的发生率。

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函数的情况下使用类来做到这一点(这是可能的,但我怀疑这是一种特别好的方法)。我可以制作一个静态成员(例如sum_S)来跟踪总数,并在每次事件发生时更新它,但这可能不适合所有成员,我不确定当涉及到比率时,总数是否可能不会慢慢偏离真实值。

是否有一种方法可以编写单个sum()函数,该函数将我想要的成员作为参数,并返回该特定成员在所有畜群中的总和?

谢谢!

标准库头文件numeric包含了accumulate函数。它并不完全是您想要的,但很容易适应:

#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和lambda。如果您的编译器不支持这些,请使用相应的c++ 03代码(push_back和functors)。

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

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 > );

所以这就是我最终得到的(在一个名为State的类中,它包含了模拟状态,包括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;
    ...
}

这对个体数(int s)和事件率(float s)都有效,并使用指向成员函数的指针来保存这些值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。这比我以前使用的繁琐的样板代码要好得多!