2014-01-30 2 views
0

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

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 как это, но он дает мне неопределенную ссылку t o `operator new [] (unsigned int). Кроме того, когда я пытаюсь получить доступ к _pins и покажу содержимое, используемое в _pins [i], оно не показывает мне, что я передал на экземпляр. Например, если я покажу, что находится на _pins [0], он должен вернуть 11, но это не так.

+0

Откуда взялась длина()? – Joky

+0

Я забыл опубликовать эту функцию, теперь обновленную. –

+0

Вы не можете передать массив функции в C++. Это ухудшает указатель, поэтому ваша функция 'length()' неверна (это должно быть очевидно, если вы объявляете '_relay' (соответственно) в качестве указателя. –

ответ

1

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

_bindings = new short[size];

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

delete[] _bindings;

+0

Я обновил свой код экземпляром (я не знаю, могу ли я это сделать).Я попытаюсь это сделать: D –

+0

Я попытался это сделать, но он дал мне эту ошибку: неопределенная ссылка на 'operator new [] (unsigned int) –

+0

Это нехорошо RAII, вы должны« никогда »не использовать delete (если только вы «написать контейнер»). – Joky

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() {}' , потому что они инициализированы в порядке декларации, и это потенциально запутывает, чтобы перечислить их другим способом в инициализация. – Edward

+0

Спасибо за ответ. Я думаю, что я понял свою проблему, но теперь у меня есть другой вопрос. Как я должен экземпляр объекта класса Relay? спасибо! –

+0

Это зависит, вы используете компилятор C++ 11? – Joky

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. Если да, то вы можете воспользоваться такими интересными вещами, как move семантика и 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 экземпляров класса. Умный компилятор может при определенных обстоятельствах оптимизировать создание таких временных рядов. Как всегда, просмотр фактического выхода ассемблера полезен для оценки конкретных методов и конкретных компиляторов.

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

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

Edit: В прискорбном случае, что у вас есть очень ограниченный компилятор C++, так как, кажется, the situation с 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; 
} 
Смежные вопросы