Конечный автомат C++ / Wpmf-конверсия

Я совсем новичок в использовании C++. Я пытаюсь реализовать на C++ конечный автомат, описанный в этой ссылке для языка C: https://barrgroup.com/Embedded-Systems/How-To/Coding- Конечные автоматы.

Я создал класс Fsm, который реализует поведение конечного автомата, и класс Machine, методы которого будут состояниями.

Код работает, но генерирует предупреждение (-Wpmf-conversions), когда я пытаюсь сохранить адрес памяти метода Machine в State state__

class Fsm
{
public:
    typedef void (*State)();
private:
    State state__;
public:
    Fsm(State state);
    void dispatch();
}; 

Fsm::Fsm(State state)
{
    state__ = state ;
} //Фсм

void Fsm::dispatch()
{
    (*state__)() ;
}



class Machine : public Fsm
{
public:
    Machine() : Fsm((State)&Machine::initial) {}       // ctor
}; 

Я использую Atmega2560 с компилятором AVR-GCC.

, 👍0

Обсуждение

Для какой строки кода генерируется предупреждение? Кроме того, почему ваш класс Fsm имеет два «общедоступных» спецификатора доступа. И почему type-def (*State)() как недействительный? Возможно, я забыл свой С++, но я не понимаю, что вы пытаетесь здесь сделать., @Paul

@Paul typedef void (*State)(); — это typedef для указателя функции на функцию без параметров и тип возвращаемого значения void. Совершенно нормально иметь несколько общедоступных, защищенных или частных разделов в классе., @Majenko

«PMF» — это указатель на функцию-член. В C++ это запрещено., @Majenko


1 ответ


Лучший ответ:

2

Указатель на функцию-член не допускается в C++. GCC может это разрешить, но жалуется на вас, потому что это нестандартно.

В C++ обычный способ работы с теми вещами, которые вам нужны, — это наследование классов.

Обычно вы создаете базовый класс Fsm, который реализует базовые функции вашего конечного автомата, а затем накладываете его поверх (создаете новый класс, наследующий Fsm). code> class) другой класс, реализующий специфические функции вашей машины. Вы можете объявлять функции в базовом классе Fsm, которые являются чисто виртуальными, то есть они существуют, но не имеют тела. Затем задача дочернего класса состоит в том, чтобы фактически реализовать эту функциональность. Затем родительский класс Fsm узнает об этих функциях и может их вызывать.

Итак, у вас должно быть что-то вроде:

class Fsm {
    public:
        void dispatch();
    protected:
        virtual void initial() = 0;
}; 

void Fsm::dispatch() {
    initial() ;
}



class Machine : public Fsm {
    protected:
        void initial() {
             Serial.println("Here");
        }
}; 

Machine mach;

mach.dispatch(); // --> "Здесь"

Fsm знает о initial(), но эта функция еще не определена. Machine реализует initial(). Затем вы создаете экземпляр Machine, который содержит все необходимое. Вызов dispatch() запускает функцию в родительском классе Fsm, который затем вызывает initial() в дочернем Machine. класс.

,