112 of 208
ZBasic Language Reference 104 ZX Microcontroller Family It should be noted that, although frequently done, it is not necessary to define a default constructor. If you don’t define a default constructor, the compiler will automatically supply one for you that performs only the fundamental initialization. A constructor that has one or more parameters, all of which have default values specified, is effectively a default constructor. One last issue that must be kept in mind when writing the code for a constructor is that, for objects defined at the module level, the constructor code will be executed before any tasks have been created. Because of this, you must avoid using any ZBasic System Library routines that rely on the multi-tasking system being initialized. In particular, the subroutines Sleep(), Delay() and related subroutines must not be used in a constructor for an object that might be defined at the object level. One way to work around this limitation is to add a special initialization method to the class that can be called from Main() to perform initialization that requires the multi-tasking system to be up and running. Another alternative for situations where a delay is needed, is to add a simple delay method to the class that effects a delay based on the changing value of Register.RTCTick. 4.5 Object Destruction Issues When an object reaches the end of its lifetime, i.e. it goes out of scope, it may need to be “cleaned up”. For example, if one or more data members are allocated string types, the memory allocated for the string store (if any) needs to be freed. The ZBasic compiler generates code that correctly deallocates string members of objects just as it does for individual string variables and structure members that are allocated string types. Beyond that automatic cleanup activity, you may need to perform additional “cleanup” operations at the end of an object’s life. For example, if your object acquires other resources that need to be released, e.g. a semaphore or memory allocated using System.Alloc(), you need to handle these operations yourself by writing an optional class method called a destructor. A class may have at most one destructor which is a parameterless subroutine with the special name _Destroy. In the code for your destructor you only need to handle the data members that aren’t automatically handled by the compiler. For example, you needn’t be concerned with string deallocation because that is handled automatically. The automatically generated cleanup code is executed after the code in your destructor executes. 4.6 Object Assignment Issues A third optional method, known as an assignment constructor, may be defined to ensure that the assignment of one object to another (necessarily of the same type) is carried out properly. An assignment constructor is a subroutine with the special name _Assign() that takes a single ByVal parameter with the same type as the class. For most classes, it isn’t necessary to define an assignment constructor because the ZBasic compiler correctly handles object assignment. For data members that are allocated strings, the compiler generates code that frees of the destination object member’s existing string and then creates a copy of the source object member’s string. For data members that are objects, the compiler generates code that invokes the object’s assignment constructor or, if it has none, the default assignment process for that object. The same strategy is employed for data members that are structures having allocated string members. However, for all other data members the compiler generates code that performs a simple byte-wise copy. If your class has data members that have special requirements, e.g. a data member that is an address of a block of memory allocated with System.Alloc(), you’ll need to write your own specialized assignment constructor. It is important to note that if you do provide an assignment constructor, you are responsible for handling every data member of the class, not just those that require special treatment. An example of an assignment constructor for the MyTime class is shown below. In this case, the explicit assignment constructor is superfluous since it does no more than the default assignment process does. If an assignment constructor is not needed, it is advisable not to create one because it introduces a possible source of problems if new data members are added to the class and the assignment constructor is not updated to handle the new members.