Alec Fenichel
Alec Fenichel

Reputation: 1317

C++ method for array of objects

I have created a class in C++. Each object corresponds with an I/O pin on a microcontroller. I can create an array of the objects and then set each pin to an output with a for loop. I would like to be able to set multiple pins to an output at the exact same time. This can be done with the hardware.

I am trying to create a method that works on an array of objects. You would use it like this:

Pin myPins[] = {0,1,2};
myPins.setOuput();

Basically I want to create a method that works on an array of objects. Is it possible to create a setOuput method like this? If yes, how? Thanks.

Update 1

New non-member method

void setOutput(Pin pins[], int size) {
    volatile uint8_t* _DDR = pins[0].getDDR();
    uint8_t _offset = 0;
    for (int i = 0; i < size; i++) {
        _offset |= pins[i].getOffset();
    }
    DDR_HIGH;
}

I am using the _ in the names so that my existing macro works. Not great but less code.

Upvotes: 0

Views: 314

Answers (2)

Nope, you cannot add a method to a classic array the way you intend to. However, you could create a class that inherits from, say, a std::vector<Pin>, and add methods to it, like this:

class Pins : public std::vector<Pin>
{
public:
    void setOutput() { /* your code here */ }
};

That way, using C++11's uniform initialization, you could use a similar syntax:

Pins myPins = {0, 1, 2};
myPins.setOutput();

Edit: as per the comments, subclass a STL container is a quick and dirty solution and not the best idea. You could, however, create your own wrapper class very simply:

class Pins
{
    std::vector<Pin> mPins;

public:
    Pins (std::initializer_list<Pin> pins) : mPins(pins)
    { }

    void setOutput()
    {
        cout << "Pins in this pinset:" << endl;

        for (Pin & p : mPins)
        {
            cout << "\t" << p << endl;
        }
    }
};

That works exactly the same:

Pins myPins = {0, 1, 2};
myPins.setOutput();

Upvotes: 2

Daniel Jour
Daniel Jour

Reputation: 16156

Most probably your setOutput member function is reading some possibly multi byte value, changing a bit depending on the pin, and writing it back.

C++ arrays can't have member functions.

To achieve a similar effect, you should split the work your original setOutput is doing:

  1. Read some hardware config
  2. Do the bit twiddling
  3. Apply the changes

Then you can let multiple pins do their bit twiddling before applying the final output.

Example:

Pin::Config cfg = Pin::read_config();
// the following could also happen in a loop over an array.
cfg = pin1.enableOutput(cfg);
cfg = pin4.enableOutput(cfg);
// or pass by reference and mutate, if you
// want a less functional style
// e.g. pinN.enableOutput(cfg)!
Pin::write_config(cfg);

This way you still have good encapsulation, but better control. Then you can write a free function to operate on arrays, vectors or whatever collection of pins, if needed:

template<typename It>
void setOutputPins(It start, It end) {
  Pin::Config cfg = Pin::read_config();
  for (; start != end; ++start) {
    cfg = (*start).enableOutput(cfg);
  }
  Pin::write_config(cfg);
};

Using it with C arrays:

Pin array[5]; // or a pointer for dynamic arrays
// ...
setOutputPins(array, array + size);

Don't make everything OO. It'll make your life harder.


[...] a function that returns the offset value for each Pin [...]. Then I bitwise or them all together.

So you don't even need that reading step. And since you bitwise or them, you could even do something like this:

Pin::write_config(pin1.output_mask() | pin4.output_mask());

You can make the function generic, too: Or pass a member function pointer:

template<typename It>
void setPins(It start, It end, Pin::Config (Pin::*fn)(void)) {
  Pin::Config cfg = 0; // identity for bitwise or
  for (; start != end; ++start) {
    cfg |= ((*start).*fn)();
  }
  Pin::write_config(cfg);
};

And the pass a pointer to the member function you want to invoke:

setPins(array, array + size, &Pin::asInput);

Example here.

Upvotes: 0

Related Questions