Не удается успешно реализовать синглтон
Я провел большую часть сегодняшнего дня, пытаясь понять, почему я не могу заставить это работать...
У меня есть этот проект, где из-за предыдущих конструктивных соображений был реализован класс singleton, который инициализирует кучу отдельных датчиков в этой системе, которую я запускаю.
Первоначально система была построена для частиц Бора, но теперь я пытаюсь заставить ее работать с Adafruit Feather M0, поэтому мне пришлось реорганизовать несколько вещей и опустить множество строк конкретных RTOS частиц.
Однако, делая это, я обнаруживаю, что мой класс singleton больше не работает.
Датчики.h:
.
.
.
class Sensors{
static Sensors *instance;
public:
static Sensors *getInstance() {
if (!instance) {
instance = new Sensors;
}
return instance;
}
}
private:
Sensors();
.
.
.
Sensors.cpp:
.
.
.
Sensors::Sensors() : dht22(DHTPIN, DHTTYPE) {
#ifdef PLATFORM_ID
sensorLog("app.Sensors");
#endif
}
.
.
.
main.ino:
.
.
.
// Датчики
Sensors *Sensors::instance = nullptr;
Sensors *allSensors = allSensors->getInstance();
void setup(){
.
.
.
Когда я пытаюсь скомпилировать это с помощью ArduinoISP, независимо от того, что я пытаюсь, я получаю следующую ошибку:
sketch/main.ino.cpp.o: in function `Sensors::getInstance()':
sketch/lib/Sensors/src/Sensors.h:23: undefined reference to `Sensors::Sensors()'
collect2: error: ld returned 1 exit status
exit status 1
[Error] Exit with code=1
Я пробовал такие вещи, как смена линии
instance = new Sensor;
Для
instance = new Sensor();
сделать экземпляр
общедоступным, изменить конструктор датчиков, но все это безрезультатно. Может ли это быть проблемой компилятора? Почему это работает на древесностружечной плите, но не на Adafruit Feather M0?
@christopolise, 👍1
Обсуждение2 ответа
Синглтоны - это не вещь в Arduino. Конечно, вы могли бы это сделать, но в общем случае вы создали бы класс, а затем создали бы экземпляр глобального объекта для этого класса. Чаще всего этот глобальный объект создается в самой библиотеке, а не в скетче.
Если вы не используете продвинутый чип с RTOS (например, ESP32) и не используете потоки этого RTOS в значительной степени, нет никакой пользы от наличия синглтона.
Но чтобы ответить на ваш вопрос: это, вероятно, потому, что вы пытаетесь использовать конструктор Sensors()
за раз до того, как компилятор узнает, что такое конструктор Sensors ()
. Вам придется добавить какую-то форму прямого объявления, чтобы компилятор знал, что вы имеете в виду, когда говорите о конструкторе Sensors ()
. В общем-то все просто:
class Sensors;
в верхней части вашего заголовка, прежде чем класс будет фактически определен, может помочь в этих ситуациях;
Или OP может просто переместить частный конструктор из частного раздела выше публичного раздела. Тогда он должен быть закрытым (потому что выше модификатора нет, а по умолчанию используется private) и объявлен перед его использованием., @Peter Paul Kiefer
@PeterPaulKiefer, порядок членов класса в объявлении класса не имеет значения, @Juraj
@Juraj Ты прав. Пожалуйста, забудь, что я сказал. Я оставлю комментарий как пример невежества ;-) и чтобы помочь другим не иметь такого же заблуждения. Теперь я думаю, что главная проблема заключается в том, что метод getInstance
реализован в определении класса, а конструктор-нет (просто объявлен). Таким образом, вероятно, это также поможет, если мы переместим реализацию'getInstance()` в файл cpp и оставим только объявление signatur в файле hpp. Или есть причина, по которой это не сработает?, @Peter Paul Kiefer
@PeterPaulKiefer, я думаю, что cpp не компилируется, потому что он находится в какой-то папке, игнорируемой IDE, @Juraj
@christopolise Ты все еще с нами? То, что Юрай упомянул в ответе на мой последний комментарий, звучит хорошо. Файл CPP может не быть скомпилирован. Вы вели расследование в этом направлении? Юрай упомянул об этом в комментарии к ОП, но я должен извиниться за то, что не узнал его., @Peter Paul Kiefer
@Juraj Да, я согласен с вами. Ваша идея также подчеркивается тем фактом, что код работал в системе RTOS, но не после использования IDE ADUINO. Надеюсь, ОП все еще здесь, так как меня интересует окончательный ответ ;-), @Peter Paul Kiefer
У меня была такая же проблема при ссылках на классы из нескольких файлов, не забудьте поставить в верхней части вашего заголовочного файла (заканчивающегося на .h) #pragma один раз
для файлов, на которые ссылаются более одного раза!
Edit1: Кроме того, после объявления вашего класса вам нужно указать, где будет храниться ваша статическая переменная. После объявления класса напишите:
тип *Класс::переменная;
Чтобы объявить статическую переменную.
Например:
#pragma once
//#includes
class Screen
{
protected:
static void (*StateMachineStep)(int);
static SSOLED *oled;
static Player *player;
public:
Screen() {}
};
void (*Screen::StateMachineStep)(int);
SSOLED *Screen::oled;
Player *Screen::player;
Edit2: форматирование
- Как масштабировать растровое изображение (массив uint8_t) в Arduino?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Что лучше использовать: #define или const int для констант?
- Функции со строковыми параметрами
- Как работать с аналоговыми контактами в цикле?
- Какие есть другие IDE для Arduino?
- Как использовать переменные и функции в нескольких файлах .ino
- Разница между void setup() и void setup(void)
находится ли cpp в тех же папках, что и ino?, @Juraj
В отличие от RTOS, Arduino-это единственная угроза и нет ОС, на самом деле нет никакой пользы для реализации синглтона в среде Arduino..., @hcheung
private: Sensors()
находится вне вашего класса - и в конце вашего класса отсутствует требуемое;
. Ваш код в его нынешнем виде невозможно скомпилировать., @Majenko@Majenko, конструктор используется только в
getInstance
. он может быть частным и объявлен там. компилятор основывает его. ошибка при связывании, @Juraj