QM 5.1.3
Working with Class Operations

Operations attached to a class can access individual instances of the class, except for a static class operation, which is cannot access any particular instance.

In C, a non-static class operation corresponds to a function that (by a coding convention) takes the "me" pointer to the struct with class attribute (e.g., bool Calc_eval(Calc * const me, double op, uint8_t oper)).

Example of a class operation in C

In C++, a non-static class operation corresponds to a class member function, that is a function with the "this"-calling convention (e.g., (e.g., bool Calc::eval(double op, std::uint8_t oper)).

Example of a class operation in C++

Class Constructors

A constructor is a special kind of class operation that initializes an instance of its class. QM supports class constructors both for C and C++.

Class Constructors in C

In C, a constructor should be named ctor, or ctor1, ctor2, etc. if you have more constructors with different signatures (different parameters). The ctor function should have return type void. It can have any number of parameters.

Class constructor in C

This piece of the model generates the following code:

void Philo_ctor(Philo * const me) {
QActive_ctor(&me->super, Q_STATE_CAST(&Philo_initial));
QTimeEvt_ctorX(&me->timeEvt, &me->super, TIMEOUT_SIG, 0U);
}
Note
The C constructor must always call the superclass' as well as members' constructors explicitly. For example, the Philo_ctor() in the listing above calls the superclass' constructor QActive_ctor() as well as member constructor QTimeEvt_ctorX().

Invoking Constructors of Static Objects in C

In C, constructors of global/static objects are not invoked automatically, as it is the case in C++. Therefore, in C, you need to call the constructors of all your global/static objects explicitly. This often poses a problem with encapsulation of components, such as Active Objects, where you don't want to expose the whole class declaration (to get to the constructor). In that cases, the example models in QP/C use an idiom, in which the special free operation <Class>_ctor_caller() (or just <Class>_ctor()) is provided just to call the constructor.

For example, the model in the screen shot above contains the free operation Philo_ctor_call(), which is defined as follows

/* definition provided in the philo.c module */
void Philo_ctor_call(void) {
uint8_t n;
for (n = 0U; n < N_PHILO; ++n) {
Philo_ctor(&Philo_inst[n]); /* <== ctor */
}
}

This particular "ctor call" invokes constructors of all Philo instances in the system. Later, in the main() function, only the Philo_ctor_call() operation is called, without exposing the declaration of the Philo class (and its constructor):

void main(void) {
. . .
/* start the active objects... */
Philo_ctor_call(); /* <== call all Philosopher ctors */
for (n = 0U; n < N_PHILO; ++n) {
QACTIVE_START(AO_Philo[n], /* AO to start */
. . .
}
. . .
}

Class Constructors in C++

In C++, a constructor has the same name as the class and no return value. A constructor can have any number of parameters and a class may have any number of overloaded constructors. Constructors may have any accessibility, public, protected or private.

C++ Constructor Initializer List

To provide the constructor initializer list, you put the list in the code panel starting with the colon (':') optionally preceded by any number of spaces. You can continue the list for as many lines as you wish.

The constructor initializer list might be followed by the body of the constructor. To start the body, you simply leave one (or more) empty lines after the initializer. QM will interpret all lines of code after such an empty line as the body of the constructor.

Finally, you might skip the constructor initializer list altogether by simply not placing the colon (':') at the beginning.

The following screen shot shows a C++ constructor with a constructor initializer list and a body.

Class constructor in C++

This piece of the model generates the following code:

Table::Table() noexcept
: QActive(&initial)
{
for (uint8_t n = 0U; n < N_PHILO; ++n) {
m_fork[n] = FREE;
m_isHungry[n] = false;
}
}

Explicit Constructor in C++

You can make a C++ constructor explicit by providing the keyword explict in the return type filed in the Property Sheet. An example of an explicit constructor is provided in the Table constructor shown in the scren shot above.

Class Destructors

A destructor is a kind of class operation that cleans up after an instance of its class. QM supports class destructors both for C and C++.

Class Destructors in C

In C, a destructor should be named xtor. The xtor class operation should have return type void and should not take any parameters (except of the implicit me pointer).

Note
The C constructor must always call the superclass' constructor explicitly.

Class Destructors in C++

In C++, a destructor should be named ~<Class>. The destructor class operation should have no return type and should not take any parameters (except of the implicit this pointer).

Static (Class-Wide) Operations

Static class operation does not have access to any specific instance of a class, but has permissions to access any attributes of any instance of the class. In C, a static class operation does not take the "me" pointer. Similarly, in C++, a static class operation does not take the implicit "this" pointer. You make a given class operation static by checking the static checkbox in the Class Operation Property Sheet.

Class Operation Property Sheet

Class operation Property Sheet

The class operation property sheet allows you to set the following properties:

  • operation name
  • operation return type drop-down box (NOTE: accepts also user-supplied types)
  • operation specifier (C++ only) allow you to provide such specifiers as: override, noexcept, =delete, =0, etc.
  • operation virtual (C++ only) chcekbox
  • operation inline (C++ only) chcekbox
  • operation documentation for documenting the operation (see also generate comments)
  • operation code/pseudocode for specifying code of the operation (NOTE: the pseudocode box is currently not used)

Next: Working with Free Operations