Arduino C ++ класс с массивами

0

Я создаю класс, в котором должен быть массив. В настоящее время я пытаюсь передать массив, но массив может быть любого размера. Когда я пытаюсь это сделать, это не сработает. Кто-нибудь знает как это делать?. У меня в настоящее время некоторые проблемы с этим, но здесь мой код:

Relay.cpp

Relay::Relay(short pins[])
{
    _relay = pins;
    _binding = new short[length()];
    for(short i=0; i<length(); i++)
        _binding[i]=0;
}

short Relay::length()
{
    return sizeof(_relay)/sizeof(short);
}

Relay.h

class Relay
{
    public:
        Relay(short pins[]);
        short length();
    private:
        short *_relay;
        short *_binding;
};

когда я создаю экземпляр:

Relay reles((short[]){11, 10, 9, 8, 7, 3, 2, 73, 4, A0, A1, A2, A3, A4});

EDIT: после предложения резидентного бисквита я столкнулся с таким файлом cpp, но он дает мне неопределенную ссылку на ошибку "operator new [] (unsigned int)". Кроме того, когда я пытаюсь получить доступ к _pins и покажу содержимое, используемое в _pins [i], оно не показывает мне, что я передал на экземпляр. Например, если я покажу, что находится на _pins [0], он должен вернуть 11, но это не так.

  • 0
    Откуда берется length ()?
  • 0
    Я забыл опубликовать эту функцию, теперь обновлен.
Показать ещё 2 комментария
Теги:
class
arrays
arduino

3 ответа

1

Вам нужно выделить некоторую память, если вы собираетесь использовать этот подход.

_bindings = new short[size];

Не забывайте освобождать эту память, когда вы закончите с ней.

delete[] _bindings;

  • 0
    Я обновил свой код с помощью экземпляра (я тоже не знаю, смогу ли я это сделать). Я собираюсь попробовать это: D
  • 0
    Я пытался сделать это, но это дает мне эту ошибку: неопределенная ссылка на `operator new [] (unsigned int)
Показать ещё 2 комментария
0

Это, как правило, сомнительный класс, чтобы класс C++ содержал указатель на "внешние данные". Часто лучший способ сделать это состоит в том, чтобы ваш C++ использовал копию внешних данных, поэтому он очищает выделение памяти при уничтожении экземпляра класса.

Также как и кто-то еще упомянул, некоторые из этих вещей гораздо проще сделать с C++ 11. Если вы используете g++ или clang++ качестве своего компилятора, возможно, у вас уже есть поддержка C++ 11, что делает многие вещи очень приятными и легкими, особенно для работы встраиваемых систем.

В этом конкретном случае здесь полная и компилируемая программа (я использовал g++ и скомпилирован с g++ -std=C++11 -o relay relay.cpp со следующим содержимым relay.cpp. я Мы объединили все в один файл для простоты иллюстрации, но в реальной жизни вы должны сохранить разделение файлов .cpp и .h которые у вас уже есть.

#include #include

class Relay
{
    public:
        Relay(std::vector<short> pins)
            : _relay(pins), _binding(pins.size()) {}
        // these are just diagnostics for testing the class
        std::ostream& printPins(std::ostream &out) {
                for (auto i : _relay) 
                      out << i << ' '; 
                   out << std::endl; 
        }
        std::ostream& printBindings(std::ostream &out) { 
                for (auto i : _binding) 
                    out << i << ' '; 
                out << std::endl; 
        }
    private:
        std::vector<short> _relay;
        std::vector<short > _binding;
};

enum {A0=80, A1, A2, A3, A4};

int main()
{
    Relay reles{std::vector<short>{11, 10, 9, 8, 7, 3, 2, 73, 
                                 4, A0, A1, A2, A3, A4}};
    reles.printPins(std::cout);
    reles.printBindings(std::cout);
    return 0;
}

enum для линий A0 A4 только для полноты в этом примере, но они могут быть #define или const int объявлениями. Это не имеет значения.

Две функции print...() предназначены только для иллюстрации, чтобы продемонстрировать, что она действительно делает то, что ожидается. В этом случае вывод:

11 10 9 8 7 3 2 73 4 80 81 82 83 84 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 

Std :: vector является частью стандартной библиотеки и может использоваться, даже если вы не используете C++ 11. Если да, то вы можете воспользоваться такими интересными вещами, как семантика перемещения и constexpr и другие лакомства, которые особенно полезны во встроенных системах. Одна такая приятная функция называется инициализацией списка и используется в main в этой примерной программе. В этой строке:

    Relay reles{std::vector<short>{11, 10, 9, 8, 7, 3, 2, 73, 4, A0, A1, A2, A3, A4}};

Создается временный std::vector<short> а затем используется для инициализации reles класса reles. Умный компилятор может при определенных обстоятельствах оптимизировать создание таких временных рядов. Как всегда, просмотр фактического выхода ассемблера полезен для оценки конкретных методов и конкретных компиляторов.

Еще одна вещь, которую я считаю очень полезной, - это стиль for (auto i: _relay) for цикла. Это говорит, что компилятор автоматически выводит тип для i, рассматривая relay как набор чего-то. Очень кратким и очень удобным.

Если вы еще не знакомы с языком C++ (или просто относительно новыми частями), я бы рекомендовал получить книгу, такую как Stroustrup C++ Язык программирования, четвертый редактор. ,

Редактировать: В неудачном случае, когда у вас очень ограниченный C++ компилятор, как представляется, ситуация с Arduino, вам нужно будет делать что-то по-другому. В частности, поскольку у вас нет operator new или operator delete вам придется либо предварительно выделить максимальный размер для своих массивов, либо просто полагаться на те, которые передаются как часть инициализации. Вот один из способов сделать это:

#include <cassert>

class Relay
{
    public:
        Relay(int numpins, short *pins, short *bindings)
            : _numpins(numpins), _relay(pins), _binding(bindings) {}
    short pin(int i) 
    {
    if ((i < 0) || (i >= _numpins))
        return -1;
    return _relay[i];
    }
    short binding(int i)
    {
    if ((i < 0) || (i >= _numpins))
        return -1;
    return _binding[i];
    }
    private:
        int _numpins;
        short *_relay;
        short *_binding;
};

enum {A0=80, A1, A2, A3, A4};

int main()
{
    const int numpins = 14;
    short pins[numpins] = {11, 10, 9, 8, 7, 3, 2, 73, 
                           4, A0, A1, A2, A3, A4};
    short bindings[numpins] = {1, 2, 3, 4, 5, 6, 7,
                           8, 9, 10, 11, 12, 13, 14};
    Relay reles(numpins, pins, bindings);
    assert(reles.pin(0) == 11);
    assert(reles.binding(4) == 5);

    return 0;
}
0

Динамический массив в C++ находится под вектором имени. Вы звоните:

class Relay
{
    public:
        Relay(const std::vector<short> &pins) 
           : _binding(pins.size()), _relay(pins) {}
    private:
        std::vector<short> _relay;
        std::vector<short> _binding;
};


int main() {
  // C++ 11
  //  Relay r({1, 2, 3, 4});

  // C++03
  short arr[] = {1, 2, 3, 4};
  std::vector<short> v(std::begin(arr), std::end(arr));
  Relay r(v);
}

В коде есть несколько проблем, например:

short *_relay;

- указатель, sizeof (_relay) - это размер указателя, не связанный с размером выделения памяти, на которое он указывает. Поэтому sizeof (_relay)/sizeof (short); эквивалентно sizeof (short *)/sizeof (short); что на самом деле не имеет никакого смысла.

Когда вы выполните:

_relay = _pins;

вы копируете указатель, теперь _relay указывает на то же самое место _pins. Однако эта память, на которой они указывают, была "изменчивой": она временно назначена на сайте вызова. Он будет отменен, как только вызов будет возвращен. Теперь ваш указатель указывает на область, к которой вы больше не должны обращаться.

  • 1
    Я бы порекомендовал изменить строку конструктора на: `: _relay (pins), _binding (pins.length () {}`, потому что они инициализируются в порядке объявления, и это может привести к путанице при перечислении их другим способом при инициализации.
  • 0
    Спасибо за ответ. Я думаю, что понял мою проблему, но теперь у меня есть другой вопрос. Как мне создать экземпляр объекта класса Relay? Спасибо!
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню