Constructors and Destructors
 
In charge of the creation and destruction of objects.

Overview
Declaration
Default constructors
Copy constructors
Calling constructors

Overview

Constructors and destructors are responsible for creating and destroying objects, respectively. In general, constructors give objects their initial state, that is, they give meaningful values to their objects' member data. Destructors perform the opposite function; they make sure any resources owned by their objects are properly freed.

Simply, constructors are special member procedures that are called when an object is created, and destructors are special member procedures called when an object is destroyed. Both constructors and destructors are called automatically by the compiler whenever an object is created or destroyed, whether explicitly with the use of the Dim or New keywords, or implicitly by passing an object to a procedure by value or through an object going out of scope.

Declaration

Constructors and destructors are declared like member procedures but with the Constructor keyword instead of Sub or Function, and without a name. Similarly, they are defined with only the name of the Type or Class they are declared in.

A Type or Class can have multiple constructors, but only one destructor.

Default constructors

Default constructors are constructors that either have no parameters, or all of their parameters have a default value. They are called when an object is defined but not initialized, or is created as part of an array, with the Dim, ReDim or New[] keywords. The first constructor declared in the example below is a default constructor.

Copy constructors

Copy constructors are constructors called when an object is created, or cloned, from another object of the same type (or an object that can be converted to that type). This happens explicitly when initializing an object with another object, or implicitly by passing an object to a procedure by value. Copy constructors are declared having one parameter: an object of the same type passed by reference.

Copy constructors are only called when creating and initializing object instances. Assignment to objects is handled by the Member Operator Let.

Calling constructors

Unlike other member procedures, constructors are generally not called directly from an object instance. Instead, a constructor is specified in a Dim statement either with an initializer or without one, or in a New statement with or without arguments.

When specifying an initializer for an object, the name of the type followed by any arguments it requires is used.

Type foo
    '' Declare a default ctor, copy ctor and normal ctor
    Declare Constructor
    Declare Constructor (ByRef As foo)
    Declare Constructor (As Integer)

    '' Declare a destructor
    Declare Destructor

    ints As Integer Ptr
    numints As Integer
End Type

'' Define a constructor that creates 100 integers
Constructor foo
    ints = New Integer(100)
    numints = 100
End Constructor

'' Define a constructor that copies the integers from another object
Constructor foo (ByRef x As foo)
    ints = New Integer(x.numints)
    numints = x.numints
End Constructor

'' Define a constructor that creates some integers based on a parameter
Constructor foo (n As Integer)
    ints = New Integer(n)
    numints = n
End Constructor

'' Define a destructor that destroys those integers
Destructor foo
    Delete[] ints
End Destructor

Scope
    '' calls foo's default ctor
    Dim a As foo
    Dim x As foo Ptr = New foo

    '' calls foo's copy ctor
    Dim b As foo = a
    Dim y As foo Ptr = New foo(*x)

    '' calls foo's normal ctor
    Dim c As foo = foo(20)
    Dim z As foo Ptr = New foo(20)

    '' calls foo's dtor
    Delete x
    Delete y
    Delete z
End Scope '' <- a, b and c are destroyed here as well


Compiler-provided constructors and destructors

If no copy constructor is declared for a Type or Class, the compiler provides one. If no constructor has been declared, the compiler also provides a default constructor.

The compiler-provided default constructor initializes member data to default values, that is, numeric and pointer members are set to zero (0), and object members are default-constructed. The copy constructor that the compiler declares shallow-copies all member data from one type to another: numeric and pointer types are initialized with the corresponding data members in the object that is copied, and object members are copy-constructed from their corresponding object members. This means that dynamic resources, such as memory pointed to by a pointer data member, is not copied; only the address is copied. So if an object owns a resource, meaning it is responsible for its creation and destruction, then the compiler-generated copy constructor will not be sufficient.

If a destructor is not declared, the compiler generates one. This destructor calls object members' destructors and does nothing for numeric and pointer types. Again, if an object owns a dynamic resource, then the compiler-generated destructor will not be sufficient, as the resource will not be freed when the object is destroyed.

This is commonly referred to as the "Rule of 3": If an object needs a custom copy constructor, assignment operator or destructor, chances are it needs all three.