Не удается успешно реализовать синглтон

Я провел большую часть сегодняшнего дня, пытаясь понять, почему я не могу заставить это работать...

У меня есть этот проект, где из-за предыдущих конструктивных соображений был реализован класс 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?

, 👍1

Обсуждение

находится ли cpp в тех же папках, что и ino?, @Juraj

В отличие от RTOS, Arduino-это единственная угроза и нет ОС, на самом деле нет никакой пользы для реализации синглтона в среде Arduino..., @hcheung

private: Sensors() находится вне вашего класса - и в конце вашего класса отсутствует требуемое;. Ваш код в его нынешнем виде невозможно скомпилировать., @Majenko

@Majenko, конструктор используется только в getInstance. он может быть частным и объявлен там. компилятор основывает его. ошибка при связывании, @Juraj


2 ответа


0

Синглтоны - это не вещь в 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


1

У меня была такая же проблема при ссылках на классы из нескольких файлов, не забудьте поставить в верхней части вашего заголовочного файла (заканчивающегося на .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: форматирование

,