0

How do I perform the same operation on different class members without duplicating code?

I have a function which creates an object of type Farm, and then performs some kind of a calculation on its members (in this case, it prints the member variable, but the code I am currently working on is too complex to copy here in its entirety):

#include <iostream>
#include <String>

class Farm
{
public:
    int cows = 1;
    int chickens = 2;
    int mules = 3;
};

using namespace std;

void count_animals()
{
    Farm* animal_farm = new Farm;
    cout << animal_farm->chickens;
}

int main()
{
    string animals_to_count = "count my chickens";

    if (animals_to_count == "count my chickens")
        count_animals();
    if (animals_to_count == "count my cows")
        count_animals();
    if (animals_to_count == "count my mules")
        count_animals();

    return 0;
}

"Count my chickens" is hard-coded in main(). However, in the problem I am working on right now, animals_to_count will come from another function as an argument.

Is it possible to print cows/chickens/mules of animal_farm without using n if statements in count_animals, where n is the number of member variables?

To further clarify my problem: what I am trying to do is have 1 if statement in count_animals() which will identify which member of Farm is printed (change ->chickens to ->cows or to ->mules).

Is what I am trying possible? If not, are there other ways to work around this?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • It's not clear where you're going here. Are you doing the _same_ complicated operation on any of a number of identical elements of your class? And must you have something like "count_animals" or could you change that to one each of "count_chickens", "count_cows", etc.? – Tim Wescott Oct 27 '21 at 20:34
  • Yes, the operation is always the same. The only thing that's different is the member which that operation is performed on. I am trying to keep the code concise if I did "count_chickens", "count_cows", etc. I would have like ten almost identical unctions where the only difference is which member of Farm this operation is performed on. – Denis Shevchenko Oct 27 '21 at 20:37

3 Answers3

2

Putting your variables into a vector or other container may be the right answer.

Alternately, you can make a worker function (that you may wish to be private or protected), and getter functions with almost no code. This lets you write your complicated statistics-extraction once, with slim "getters" that make it visible in your preferred way.

class Farm
{
public:
    int cows = 1;
    int chickens = 2;
    int mules = 3;

    int get_cow_stats() {return get_complicated_thing(self.cows);}
    int get_chicken_stats() {return get_complicated_thing(self.chickens);}
    int get_mule_stats() {return get_complicated_thing(self.mules);}

private:
    int get_complicated_thing(int animals);
};
Tim Wescott
  • 478
  • 4
  • 14
  • Yeah, it seems that what I am trying to do is not possible and I will have to settle either for some kind of a container or a worker function. Thanks. – Denis Shevchenko Oct 27 '21 at 21:04
1

Use std::vector and constant indices:

class Farm
{
public:
    std::vector<int> animal_quantity(3);
    const int cow_index = 0;
    const int chickens_index = 1;
    const int mules_index = 2;   
};

When referring to the quantity of cows:

std::cout << animal_quantity[cow_index] << "\n";
Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • Unfortunately this method is counter productive for what I am trying to do. My real farm has 40 animals. That means I need 40 indices which will make my header file much bulkier. It is not worth it for the kind of feature I am trying to implement. I am looking for something more elegant, if you will. I appreciate it though. – Denis Shevchenko Oct 27 '21 at 20:49
1

Perhaps a pointer-to-member is what you are looking for?

#include <iostream>
using namespace std;

class Farm
{
public:
    int cows = 1;
    int chickens = 2;
    int mules = 3;
};

int Farm::* getMemberPtr(int whichMember)
{
    switch (whichMember)
    {
        case 0: return &Farm::chickens;
        case 1: return &Farm::cows;
        case 2: return &Farm::mules;
    }
    throw invalid_argument("");
}

void count_animals(int Farm::*member)
{
    Farm animal_farm;
    cout << animal_farm.*member;
}

int main()
{
    int animals_to_count = ...; // 0, 1, 2, etc
    int Farm::* member = getMemberPtr(animals_to_count);
    count_animals(member);
    return 0;
}

Online Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770