简体   繁体   中英

Loop through objects of class c++

So I have a Class with 120 obects and every object has the same Member-Variables. Something like this:

Area f1;Area f2; Area f3; Area f4; Area f5; Area f6; [...]

f1.SetCoal(1);
f2.SetCoal(0.7); f2.SetCoal(.3);
f3.SetCoal(.5950); f3.SetCopper(0.2833); f3.SetIron(0.0917); f3.SetAmber(0.025); f3.SetGold(0.005);
f4.SetCoal(.5425); f4.SetCopper(0.325); f4.SetIron(0.1025); f4.SetAmber(0.0225); f4.SetGold(0.0075);
f5.SetCoal(.49); f5.SetCopper(0.3667); f5.SetIron(0.1133); f5.SetAmber(0.02); f5.SetGold(0.01);
f6.SetCoal(.4375); f6.SetCopper(0.4083); f6.SetIron(0.1242); f6.SetAmber(0.0175); f6.SetGold(0.0125);  [...]

So some of these Areas get "active" by user input, setting a member-variable to TRUE. Is it possible to loop through all the Objects and check if they're active?

for (int i = 0; i <= 119; i++)
{

     if(f(i).active == true) 
     //do stuff
}

instead of

if(f1.active) //do stuff
if(f2.active) //do stuff
if(f3.active) //do stuff

You could make a std::vector of all your areas and initialize them with their start values with an initializer list. Then you can loop over them using the range based for loop.

#include <vector>

class Area {
    double m_coal;
    double m_copper;
    double m_iron;
    double m_amber;
    double m_gold;

    bool m_active;
public:
    Area(double coal, double copper, double iron, double amber, double gold) :
        m_coal(coal), m_copper(copper), m_iron(iron), m_amber(amber), m_gold(gold), m_active(false)
    {}
    bool is_active() const { return m_active; }
};

int main() {
    // initialize all areas
    std::vector<Area> areas = {
        {1., 0., 0., 0., 0.},
        {0.7, 0., 0., 0., 0.},
        {.5950, 0.2833, 0.0917, 0.025, 0.005}
    };

    for (auto& area : areas) {
        if (area.is_active()) {
            // do stuff
        }
    }
}

If you want to take it one step further, you can make it easier to handle your resources by putting them in a std::array . You may want to extend the list of resources one day which will be very time consuming if they are all hardcoded everywhere. A softer approach could be something like this:

#include <iostream>
#include <initializer_list>
#include <array>
#include <vector>

// append to the list when you invent a new resource
enum Resource : size_t { coal, copper, iron, amber, gold, LAST=gold, COUNT=LAST+1 };

class Area {
    std::array<double, Resource::COUNT> m_resources;
    bool m_active;
public:

    Area(std::initializer_list<double> il) :
        m_resources(),
        m_active(false)
    {
        std::copy(il.begin(), il.end(), m_resources.begin());
    }

    double get(Resource x) const { return m_resources[x]; }
    void set(Resource x, double value) { m_resources[x]=value; }
    void add(Resource x, double value) { m_resources[x]+=value; }

    void set_active() { m_active=true; }
    void set_inactive() { m_active=false; }
    bool is_active() const { return m_active; }
};

int main() {
    // initialize all areas
    std::vector<Area> areas = {
        {1.},
        {0.7},
        {.5950, 0.2833, 0.0917, 0.025, 0.005},
        {.1232, 0.3400, 0.0000, 0.234, 0.001}
    };

    areas[0].set_active(); // just for testing
    for (auto& area : areas) {
        if (area.is_active()) {
            // do stuff
            std::cout << "coal before: " << area.get(coal) << "\n";
            area.add(coal, -0.1);
            std::cout << "coal after : " << area.get(coal) << "\n";
        }
    }
}

Try something like this:

#include <vector>

std::vector<Area> f(120);

f[0].SetCoal(1);
f[1].SetCoal(0.7); f[1].SetCoal(.3);
f[2].SetCoal(.5950); f[2].SetCopper(0.2833); f[2].SetIron(0.0917);
//...

for(auto & a: f)
{
     if(a.active == true) 
     //do stuff
}

You can use a C++ preprocessor, possibly with Boost.Preprocessor library extension:

#include <iostream>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/comparison/not_equal.hpp>
#include <boost/preprocessor/repetition/for.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

#define PRED(r, state) \
  BOOST_PP_NOT_EQUAL( \
    BOOST_PP_TUPLE_ELEM(2, 0, state), \
    BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 1, state)) \
  ) 

#define OP(r, state) \
  ( \
    BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 0, state)), \
    BOOST_PP_TUPLE_ELEM(2, 1, state) \
  ) 

#define INIT(r, state) \
  BOOST_PP_CAT(x.var, BOOST_PP_TUPLE_ELEM(2, 0, state)) = \
    BOOST_PP_TUPLE_ELEM(2, 0, state));

#define PRINT(r, state) \
 std::cout << BOOST_PP_CAT(x.var, BOOST_PP_TUPLE_ELEM(2, 0, state)) << ", ";

struct X {
    int var1, var2, var3, var4, var5;
};

int main() {
    X x;
    BOOST_PP_FOR((1, 5), PRED, OP, INIT)
    BOOST_PP_FOR((1, 5), PRED, OP, PRINT)
}

Note that this is just a demo how to iterate over (member) variables named varI , where I goes from 1 to 5. You can eventually modify it for your problem.

Also note that such a solution is terribly ugly and difficult to maintain. I just posted it because it can be done , but would strongly advise to store those variables into some array form, as others suggested.

Live demo: https://wandbox.org/permlink/rpGg9iKVkrI3SCtM

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM