Как перебрать экземпляры классов в предопределенном порядке в C ++? - PullRequest
0 голосов
/ 10 февраля 2020

Я ищу чистый способ чтения данных из всех моих экземпляров класса, имеющего дело со встроенными чипами в том порядке, в котором они были объявлены с одной функцией, которую я мог бы объявить как часть самого класса.

Функция должна была бы проверить, сколько экземпляров класса было создано в моей программе (я думаю, что я понял эту часть), затем проверить, в каком порядке они были объявлены, но я не уверен, что моя стратегия это лучший подход:

class input_shift_reg
{
public:
    input_shift_reg();
    int shift_ID; //keeps count of which instance # this is
    int data; // stores data from the chip when read
    int *ptr_to_data; //
    };

input_shift_reg::input_shift_reg()
{
    shift_ID = nb_of_input_shift_reg_objects++;
}

void inputShiftSnapShot() //take a 74hc165 snapshot of the data on the 74hc165 and // transfer it via SPI protocol to the arduino
{

    PORTD &= ~(1 << loadPin); //ask the chip for a snapshot (this part is working alright)
    delay(1);
    PORTD ^= (1 << loadPin);

// This is the part that needs to transfer varying on the number of class instances. 
for(int i = 0; i < nb_of_input_shift_reg_objects; i++)
{
    // HERE IS MY PROBLEM: it needs to transfer to the data member of each inst in right order
    data = SPI.transfer(0x00);
}
}

Так что мне просто нужен способ для inputShiftSnapShot () проверить, каково значение элемента shift_ID всех созданных экземпляров класса, и SPI.transfer () для каждых данных. член в правильном порядке. пример:

    input_shift_reg shift_1();
input_shift_reg shift_2();

inputShiftSnapShot(); // this would transfer to shift_1.data first, then to shift_2.data second.

Как я могу это сделать ?? Спасибо!

1 Ответ

0 голосов
/ 10 февраля 2020

Вот один из подходов, использующий stati c контейнер указателей экземпляров.

Следует иметь в виду, что каждая конструкция / разрушение input_shift_reg будет иметь побочные эффекты, а именно обновление s_instances контейнер. То есть, если ваш существующий код копирует их, передавая их по значению в функции, у вас будет много обновлений для instances deque.

Еще одна потенциальная проблема, о которой следует быть осторожным, - это ошибка, подобная повторному входу, если вы создаете / уничтожаете input_shift_reg объекты, перебирая контейнер экземпляров.

template <typename T>
class tracked
{
    static std::deque<T*> s_instances; 

public:
    static const std::deque<T*>& instances() { return s_instances; }
    static std::size_t number_instances() { return s_instances.size(); }

protected:
    tracked() 
    { 
        s_instances.push_back(this); 
    }

    ~tracked() noexcept()
    { 
        auto it = std::find(s_instances.begin(), s_instances.end(), this);
        assert(it != s_instances.end());
        s_instances.erase(it);
    }
};


class input_shift_reg : public tracked<input_shift_reg> {
   /*  ...  */
};

void inputShiftSnapShot()
{
    // Perform snapshot.
    PORTD &= ~(1 << loadPin); 
    delay(1);
    PORTD ^= (1 << loadPin);

    for (input_shift_reg* reg : tracked<input_shift_reg>::instances())
    {
        // Use `reg` to update instance.
        reg->set_data(...);
    }
}

Если вы не хотите усложнять stati c членов, вы можете сделать deque of pointers обычной переменной-членом и заставить вызывающих создать input_shift_reg, вызывая некоторую функцию create(...) в объекте, похожем на пул. В этом случае вы захотите сделать объекты не копируемыми и неподвижными, чтобы пул не выходил из синхронизации c с объектами.

...