Возникла проблема с доступом к значениям из указателя
Контекст
Возможно, это больше вопрос по C++, чем по Arduino, но он касается arduino C++, поэтому я решил начать здесь.
Я создаю класс для абстрагирования простой мелодии, которую я хочу использовать в проекте. У меня все работало процедурным образом, поэтому я начал перемещать все в заголовок и файл cpp (все еще новая для меня территория).
Общая концепция заключается в том, что я хочу вызвать общедоступный метод своего класса, чтобы мой код мог воспроизводить определенную мелодию. Я определил перечисление для каждой доступной мелодии, и в моем методе playMelody()
я использую пару указателей и оператор switch, чтобы получить конкретные частоты и длительность, необходимые для воспроизведения конкретной мелодии. Эти значения частоты и продолжительности хранятся в закрытых массивах класса.
Вот заголовок:
// MelodyPlayer.h
enum MELODY
{
SHAVE_AND_A_HAIRCUT = 0,
IDLE,
READY,
PROCESSING,
COMPLETE,
};
class MelodyPlayer
{
uint8_t speakerPin;
int melody_shaveAndAHairCut[9];
int durations_shaveAndAHairCut[9];
int *activeMelody;
int *activeDurations;
void _playMelody();
public:
MelodyPlayer(uint8_t speakerPin);
void playMelody(MELODY name);
};
MelodyPlayer::MelodyPlayer(uint8_t pin)
{
speakerPin = pin;
int melody_shaveAndAHairCut[] = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4, 0};
int durations_shaveAndAHairCut[] = {
4, 8, 8, 4, 4, 4, 4, 4, 4};
}
void MelodyPlayer::playMelody(MELODY name)
{
switch (name)
{
case SHAVE_AND_A_HAIRCUT:
Serial.println("Shave and a hair cut");
activeMelody = melody_shaveAndAHairCut;
activeDurations = durations_shaveAndAHairCut;
break;
}
_playMelody();
}
А вот и реализация:
// MelodyPlayer.cpp
void MelodyPlayer::_playMelody()
{
Serial.println("Playing Melody");
// * pulled from the toneMelody arduino example
for (int thisNote = 0; thisNote < 8; thisNote++)
{
int activeDuration = activeDurations[thisNote];
int noteDuration = 1000 / activeDurations[thisNote];
int noteFrequency = activeMelody[thisNote];
Serial.println(thisNote);
Serial.println(activeDuration);
Serial.println(noteDuration);
Serial.println(noteFrequency);
tone(speakerPin, noteFrequency, noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
noTone(speakerPin);
}
}
И я вызываю это в своем файле .ino
следующим образом:
MelodyPlayer player = MelodyPlayer(SPEAKER);
player.playMelody(SHAVE_AND_A_HAIR_CUT);
Проблема
Я загружу скетч и все заработает. Проблема, с которой я сталкиваюсь, заключается в том, что когда я получаю частный метод _playMelody()
, значения, которые я получаю для activeDuration
, noteDuration
и noteFrequency
абсолютно неверны:
Я предполагаю, что делаю что-то не так с настройкой и получением значений через переменную-указатель, которую я установил в операторе switch, но я не уверен, где я ошибаюсь.
Вы можете увидеть/вытащить фактический код из abstracting-to- class ветвь моего репозитория, если вы хотите покопаться.
Я выполнил похожий динамический выбор через указатель в доказательстве концепции ранее, но он был написан процедурно, а не классифицирован. Не могу понять, в чем разница :|
Есть идеи?
@Chris Schmitz, 👍0
Обсуждение1 ответ
Лучший ответ:
Как упомянул Майенко в комментарии, вы создали новые локальные массивы в конструкторе, но никогда ничего не помещали в массивы-члены классов. Они имеют одно и то же имя, но не являются одной и той же переменной. За создание новой переменной отвечает ключевое слово int. Однако вы не можете просто присвоить значения массива, просто опуская int. Есть несколько вариантов:
Можно заполнить массив для каждого индекса:
durations_shaveAndAHairCut[0] = 1;
Вы можете скопировать локальный массив в переменную-член с помощью memcpy:
memcpy((void*)this->durations_shaveAndAHairCut, (void*)durations_shaveAndAHairCut, 9*sizeof(int));
Вы можете объявить массивы статическими в объявлении класса и инициализировать их вне конструктора в MelodyPlayer.cpp:
int MelodyPlayer::durations_shaveAndAHairCut[] = { 4, 8, 8, 4, 4, 4, 4, 4, 4};
Я предпочитаю последний вариант.
Потрясающий! Спасибо за помощь! Я пошел с последним вариантом. Это определенно кажется самым простым и прямым решением., @Chris Schmitz
- Скетч с несколькими классами (.h и .cpp) – как соединить классы
- Передача двумерного массива в функцию
- Как работают массивы?
- Как передать объект Encoder конструктору другого класса
- Сбой при использовании переменных ссылок в классах
- Есть ли способ воспроизводить звуки с Arduino без использования звукового экрана?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
Ваши массивы мелодии и длительности, содержащие фактические данные, являются локальными для конструктора. Кроме того, они не используются, поэтому компилятор их оптимизирует., @Majenko