Menu

Encapsulating Active Objects and QM code generation

2025-12-02
2025-12-05
  • andrew frank

    andrew frank - 2025-12-02

    Hi, I have a question about the use of QM.
    I created a state machine class named VMod. VMod mod[N] is created as needed in the user program. Therefore, I need to define the VMod structure in vmod.h, but there is no need to declare the internal state functions of VMod. However, using $declare {VMod} will generate all methods of the class by default. Is there a solution?

     
  • Quantum Leaps

    Quantum Leaps - 2025-12-02

    Hi Andrew,
    Yes, the directive $declare {VMod} generates the whole class VMod, which includes all class members: both data members and member functions. State-handler functions are member functions (they need the me instance pointer), so they are included. This is exactly as in C++, where a valid class declaration requires all members.

    But your problem is really not about the class declaration, but about encapsulation and information hiding. It seems to me that you're trying to go about it in the traditional "C way", where you expose the VMod struct (the data members) in a header file, but want to hide the member functions from this header file.

    All provided examples for QP/C illustrate a different approach--with a much better encapsulation. Specifically, the DPP (Dining Philosophers Problem) application also contains an array of the Philo active objects. But this array is statically allocated in the philo.c implementation file:

    //$declare${AOs::Philo} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    
    //${AOs::Philo} ..............................................................
    typedef struct Philo {
    // protected:
        QActive super;
    
    // private:
        QTimeEvt timeEvt;
        uint8_t id;
    
    // public:
    } Philo;
    
    extern Philo Philo_inst[N_PHILO];
    . . .
    

    As you can see, the whole $declare${AOs::Philo} directive is inside the C file, and specifically is not exposed in any header file.

    Instead, the dpp.h header file only exposes the "opaque pointers" to the Philo AOs (as well as the Table AO)

    //${Shared::AO_Philo[N_PHILO]} ...............................................
    extern QActive * const AO_Philo[N_PHILO];
    
    //${Shared::Philo_ctor} ......................................................
    void Philo_ctor(uint_fast8_t const id);
    
    //${Shared::AO_Table} ........................................................
    extern QActive * const AO_Table;
    
    //${Shared::Table_ctor} ......................................................
    void Table_ctor(void);
    //$enddecl${Shared} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    Please study the DPP examples and the structure of the QM model file (dpp.qm), which are provided many times over in the qpc\examples directory. I hope you will like the "opaque pointer" pattern.

    --MMS

     
  • andrew frank

    andrew frank - 2025-12-03

    Hi Dr Samek! Thank you for your help!
    The essence of my purpose is to have the number of user-maintainable instances, which can be achieved entirely by controlling the macro like N without having to expose the structure definition itself, thank you very much.

     
  • andrew frank

    andrew frank - 2025-12-05
    Post awaiting moderation.
  • andrew frank

    andrew frank - 2025-12-05
     

    Last edit: andrew frank 2025-12-05

Log in to post a comment.