Structure in a class

I would like the benefit of a structure so that I can use a pointer to loop through it’s elements. But I would also like to reference the elements without having to reference the structure.

Is there a way to do that?

For example, say I have a class “fruit” that has properties including bananas, apples, pears, etc. I would like to have an instance of fruit, say “myfruit”, and simple refer to the bananas as myfruit.bananas. But if I package the properties as a structure then I would end up with something like myfruit.f.bananas whereas I would rather just write myfruit.bananas. Does that make sense?

To be a little more concrete, here are two examples. The second one has the properties in a struct.

class fruit {

public:
  fruit() {}

  int getTotal()
  {
    int total = bananas + oranges + apples + pears + grapes;
    total += kiwis + peaches + plums + watermelons;
    total += papayas + cherries + tangerines;
    return total;
  }


  uint8_t bananas;
  uint8_t oranges;
  uint8_t apples;
  uint8_t pears;
  uint8_t grapes;
  uint8_t kiwis;
  uint8_t peaches;
  uint8_t plums;
  uint8_t watermelons;
  uint8_t papayas;
  uint8_t cherries;
  uint8_t tangerines;
};
struct FRUITS {
  uint8_t bananas;
  uint8_t oranges;
  uint8_t apples;
  uint8_t pears;
  uint8_t grapes;
  uint8_t kiwis;
  uint8_t peaches;
  uint8_t plums;
  uint8_t watermelons;
  uint8_t papayas;
  uint8_t cherries;
  uint8_t tangerines;
};

class fruit {

public:
  fruit() {}

  int getTotal()
  {
    uint8_t total = 0;
    uint8_t *p = (uint8_t *)&f;
    for (uint8_t i=0; i<sizeof(FRUITS); i++)
      total += *p++;
    return total;
  }

  FRUITS f;
};

I would like the benefit of a structure so that I can use a pointer to loop through it's elements

But a structure's members can be different data types - how will the pointer know how much to increment by?

Because in this case they're all the same type.

So is it impossible to do this?

It's not impossible, but if they're all the same type, isn't an array more appropriate?

It's also potentially not portable if alignment criteria have to be met (not a problem on AVR, but maybe on Arm)

...I can use a pointer to loop through it's elements.

Why do you want to loop through the elements? To save some typing?

They're the same type but referencing ".bananas" is more meaningful than ".fruit[12]" and easier than ".fruit[BANANAS_OFFSET]" or something like that.

I want to loop in order to minimize code size.

But is looping through a structure with a pointer not portable? If so then I have some other code I have written that will need to be revisited.

Have you considered the union?

But is looping through a structure with a pointer not portable?

I can think of one potential problem that does not typically apply to 8 bit processors.

Edit: @AWOL mentioned the problem above.

How would you use a union to do this?

union FRUITS 
{
  struct 
  {
    uint8_t bananas;
    uint8_t oranges;
    uint8_t apples;
    uint8_t pears;
    uint8_t grapes;
    uint8_t kiwis;
    uint8_t peaches;
    uint8_t plums;
    uint8_t watermelons;
    uint8_t papayas;
    uint8_t cherries;
    uint8_t tangerines;
  };
  uint8_t AsArray[12];
};

If you give up the anonymity of the struct the array can be sized automatically by the compiler.

I still don’t see how that helps.
What am I missing in the example below?

union FRUITS
{
  struct
  {
    uint8_t bananas;
    uint8_t oranges;
    uint8_t apples;
    uint8_t pears;
    uint8_t grapes;
    uint8_t kiwis;
    uint8_t peaches;
    uint8_t plums;
    uint8_t watermelons;
    uint8_t papayas;
    uint8_t cherries;
    uint8_t tangerines;
  };
  uint8_t AsArray[12];
};

class fruit {

public:
  fruit() {}

  int getTotal()
  {
    uint8_t total = 0;
    uint8_t *p = (uint8_t *)&f.AsArray;
    for (uint8_t i=0; i<sizeof(FRUITS); i++)
      total += *p++;
    return total;
  }

  FRUITS f;

};

fruit myfruit;

void setup()
{
  myfruit.f.bananas = 3;
}

void loop() {}

It eliminates the pointer dung…

int getTotal()
{
  uint8_t total = 0;
  for (uint8_t i=0; i<sizeof(f.AsArray); i++)
    total += f.AsArray[i];
  return total;
}

It clearly indicates to the person performing maintenance (the future you) what was intended.

It is easier to loop over subsets of the fields.

It is easier to port (after including packing compiler directives).

It is safer to port (after including packing compiler directives).

It is possible to access the fields by index or name.

Look at the code in this link.

http://cpp.sh/2253

My combined ignorance and stupidity must be trying. But I still can't put it together.

CodingBadly: I don't want to have to use the "f." part of the reference.
I want to be able to write "myfruit.bananas".

HazardsMind: In your example, how do I reference the structure elements in a loop?

class fruit 
{
public:
  fruit() {}

  union
  {
    struct 
    {
      uint8_t bananas;
      uint8_t oranges;
      uint8_t apples;
      uint8_t pears;
      uint8_t grapes;
      uint8_t kiwis;
      uint8_t peaches;
      uint8_t plums;
      uint8_t watermelons;
      uint8_t papayas;
      uint8_t cherries;
      uint8_t tangerines;
    };
    uint8_t AsArray[12];
  };

  int getTotal()
  {
    uint8_t total = 0;
    for (uint8_t i=0; i<sizeof(AsArray); i++)
      total += AsArray[i];
    return total;
  }
};

fruit myfruit;

void setup( void )
{
  myfruit.bananas = 17;
  Serial.begin( 115200 );
  Serial.println( myfruit.getTotal() );
}

void loop( void ) { }

Thank you, and sorry to make you dot every i and cross every T.

Someday I am going to have to learn C++.

You are welcome.

First, a c++ class, for all practical purposes, already IS itself a structure, and can be treated in exactly the same way. You can access members of a structure using a pointer to the structure, and you can do the same thing with a pointer or a reference to an instance of a class, using exactly the same syntax. So, creating a structure within a class, simply to make external access to that structure easier, will actually do exactly the opposite.

Regards,
Ray L.

In this instance I'm interested in internal access to the structure, by some of the class methods. Does that change what you're saying?

To be honest, I am such a bad C++ programmer (or is it c++?) that more often than not I work by example. When I can't find one that's applicable I flounder, trying things somewhat randomly, often giving up and doing it a less elegant way. On my own I doubt I would have figured out what CodingBadly did.

The key difference between a class and a struct is that for the struct, access to members is public by default, whereas for the class, the default is private.