Classes

Tip: To create new class, you can use menu File -> New -> New Class.

See also: QM classes tutorial

 

Most programming languages have classes. A class is an user-defined type that also has functions. To understand classes, you have to be familiar with variables, user-defined types and user-defined functions.

 

In QM, classes are defined in the same way as types. Types and classes have all the same features. The only difference is that you use keyword class instead of type, and it only changes icon in the popup list of global identifiers from to .

Member functions

To add a member function to a class, create new item of 'Member function' type (menu File -> New -> New Member Function), and give it name consisting of type name, period and function name. For example, to add member function Func to type Class, create new member function Class.Func. To call member function Func, use syntax var.Func(), where var is variable of that type. Example:

 

class Class a b c ;;define class Class
Class var ;;create variable var of Class type
var.Func(args) ;;call function Func that is member of Class

 

A member function is common to all variables of that type, therefore the function doesn't know name of variable for which it is called. To access members of that variable, use simply member name, or syntax this.member. Special variable this is reference to variable for which current member function is called. It can be used only in member functions. For example, to access member c, you can use simply c, or this.c. To call other member function Func2, you can use simply Func2(args), or this.Func2(args).

 

You cannot use a class (as well as a simple type) if macro containing class definition is not compiled. To make a class always available, place it's definition (or #compile) into the init2 function or some other function that runs at startup. However you can create/delete/rename member functions at any time.

 

You also can add member functions to user-defined types and even to intrinsic types.

Special member functions

A class (only user-defined) can have three special functions - constructor, destructor and operator =. These functions cannot be called explicitly. They are recognized by item name.

 

  Item name Description
Constructor Class is called implicitly when variable is created. Must not have arguments. Must not return a value.
Destructor Class. is called implicitly when variable must be destroyed (goes out of scope). Must not have arguments. Must not return a value.
Operator = Class= is called implicitly when copying (simple assignment, function arguments, etc). Must have single argument of Class& type. Must not return a value. Should properly copy members. For types that don't have operator =, is performed memberwise copying.

 

Here Class is class name. For example, if you want to add destructor to class Abc, create member function and name it Abc..

 

Constructor and destructor of global variables are executed in QM main thread. Constructor is executed when compiling, destructor - before unloading file.

 

Elements of ARRAY cannot have constructor, but can have operator = and destructor. Destructor of ARRAY elements is called in ascending order.

Inheritance

New classes can be derived from existing classes (extend them) using a mechanism called "inheritance". Classes that are used for derivation are called "base classes" of a particular derived class. In class definition, colon before first member makes it base class of class being defined. Members (variables and functions) of base class are accessible from derived class. Members of derived class override members of base class with same name. Example:

 

type Base a b c
class Derived :Base'x c d e
Derived der
der.a=5 ;;same as der.x.a=5
der.c=5 ;;not der.x.c
der.x.c=5

 

Members of base type can be accessed directly (e.g. der.a) or through the member name (e.g. der.x.a). If the member name in the declaration is omitted (QM 2.2.0), to access base members can be used the base type name. Example:

 

type Base a b c
class Derived :Base c d e
Derived der
der.a=5 ;;same as der.Base.a
der.Base.a=5

 

Derived class, base classes and members can have constructors and destructors. When creating a variable of derived class, at first all memory is filled with 0, then are called constructors for base classes, then for members (in order they are defined), then for derived class. Destructors are called in reverse order.

Protected, private and hidden members

Private members can be accessed only from member functions of that class. Protected members also can be accesses from member functions of derived classes. To make a member function protected or private, use the Properties dialog. To make a data member (or base) protected or private, place one or two hyphens before it in class definition. Example:

 

type Base a b
class Derived :-Base'base --c d
Derived der
der.d=5 ;;OK: member is public
der.c=5 ;;error: member is private
der.b=5 ;;error: base is protected

 

If member's name begins with two underscores, or function is in private folder, it is not shown in the popup list of members, unless you are editing a member function (this. ...), or use Ctrl+Shift+. .

Variables in dynamic memory

Local variables of class type are allocated on the stack (like all local variables). To allocate a variable in dynamic memory, declare pointer and call function _new. It allocates memory and calls constructor. The _new function also can be used to allocate an array. When the variable is no longer needed, call function _delete. It calls destructor and frees memory. Example:

 

MyClass* c._new
...
c._delete