Я создаю класс, в котором должен быть массив. В настоящее время я пытаюсь передать массив, но массив может быть любого размера. Когда я пытаюсь это сделать, это не сработает. Кто-нибудь знает как это делать?. У меня в настоящее время некоторые проблемы с этим, но здесь мой код:
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, но это не так.
Вам нужно выделить некоторую память, если вы собираетесь использовать этот подход.
_bindings = new short[size];
Не забывайте освобождать эту память, когда вы закончите с ней.
delete[] _bindings;
Это, как правило, сомнительный класс, чтобы класс 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;
}
Динамический массив в 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. Однако эта память, на которой они указывают, была "изменчивой": она временно назначена на сайте вызова. Он будет отменен, как только вызов будет возвращен. Теперь ваш указатель указывает на область, к которой вы больше не должны обращаться.