Object instance data is contained in named IDL structures. We will use the term classstructure to refer to IDL structures containing object instance data.
Beyond the restriction that class structures must be named structures, there are no limits on what a class structure contains. Class structures can include data of any type or organization, including pointers and object references. When an object is created, the name of the class structure becomes the name of the class itself, and thus serves to define the names of all methods associated with the class. For example, if we create the following class structure:
struct = { Class1, data1:0L, data2:FLTARR(10) }
any objects created from the class structure Class1 would have the same two fields (data1, a long integer, and data2, a ten-element floating-point array) and any methods associated with the class would have the name Class1::method, where method is the actual name of the method routine. Methods are discussed in detail in Creating Custom Object Method Routines.
Note: When a new instance of a structure is created from an existing named structure, all of the fields in the newly-created structure are zeroed. This means that fields containing numeric values will contain zeros, fields containing string values will contain empty strings, and fields containing pointers or objects will contain null pointers or null objects. In other words, no matter what data the original structure contained, the new structure will contain only a template for that type of data. This is true of objects as well; a newly created object will contain a zeroed copy of the class structure as its instance data.
It is important to realize that creating a class structure does not create an object. Objects can only be created by calling the class name as a function or using the OBJ_NEW function, and can only be accessed via the returned object reference. In addition, object methods can only be called on objects, and not on class structures themselves.
Note: Because you can use a class name as a function, do not create a function with the same name as an existing object class.
Once defined, a given class structure type cannot be changed. If a structure definition is executed and the structure already exists, each tag name and the structure of each tag field must agree with the original definition. To redefine a structure, you must either reset or exit the current IDL session.
Automatic Class Structure Definition
If IDL finds a reference to a structure that has not been defined, it will search for a structure definition procedure to define it. (This is true of all structure references, not just class structures.) Briefly, if IDL encounters a structure reference for a structure type that has not been defined, it searches for a routine with a name of the form
STRUCT__DEFINE
where STRUCT is the name of the structure type. Note that there are two underscores in the name of the structure definition routine.
The following is an example of a structure definition procedure that defines a structure that will be used for the class CNAME.
PRO CNAME__DEFINE
struct = { CNAME, data1:0L, data2:FLTARR(10) }
END
This defines a structure named CNAME with 2 data fields (data1, a long integer, and data2, a ten-element floating-point array). If you tell IDL to create an object of type CNAME before this structure has been defined, IDL will search for the procedure CNAME__DEFINE to define the class structure before attempting to create the object. If the CNAME__DEFINE procedure has not yet been compiled, IDL will use its normal routine searching algorithm to attempt to find a file named CNAME__DEFINE.PRO. If IDL cannot find a defined structure or structure definition routine, the object-creation operation will fail.
If you are creating structure definitions on the fly, you could run into namespace conflicts. A structure with the same name as the structure you are attempting to create may already exist. This can be a problem if you are developing object-oriented applications for others, since you probably do not have much control over the IDL environment on your clients’ systems. You can avoid most problems by creating a unique namespace for your routines; NV5 Geospatial Solutions does this by prefixing the names of objects with the letters “IDL”. To help avoid namespace conflict, consider using a custom prefix (not “IDL”). To be completely sure that the objects created by your programs are what you expect, however, you should have the program inspect the created structures and handle errors appropriately.
Inheritance
When defining a class structure, use the INHERITS specifier to indicate that this structure inherits instance data and methods from another class structure. For example, if we defined a class structure called “circle,” as follows:
struct = { circle, x:0, y:0, radius:0 }
we can define a subclass of the “circle” class like this:
struct = { filled_circle, color:0, INHERITS circle }
You can use the INHERITS specifier in any structure definition. However, when the structure being defined is a class structure (that is, an object will be created from the structure), inheritance affects both the structure definition and the object methods available to the object that inherits. The INHERITS specifier is discussed in Structure Inheritance.
When a class structure inherits from another class structure, it is said to be a subclass of the class it inherits from. Similarly, the class that is inherited from is called a superclass of the new class. Defining a subclass of an existing class in this manner has two consequences. First, the class structure for the subclass is constructed as if the elements of the inherited class structure were included in-line in the structure definition. In our example, the command defining the “filled_circle” class above would create the following structure definition:
{ filled_circle, color:0, x:0, y:0, radius:0 }
Note that the data fields from the inherited structure definition appear in-line at the point where the INHERITS specifier appears.
The second consequence of defining a subclass structure that inherits from another class structure is that when an object is created from the subclass structure, that object inherits the methods of the superclass as well as its data fields. That is, if an object of the superclass type has a method, that method is available to objects created from the subclass as well. In our example above, say we create an object of type circle and define a Print method for it. Any objects of type filled_circle will also have access to the Print method defined for circle.
IDL allows multiple inheritance. This means that you can include the INHERITS specifier as many times as you desire in a structure definition, as long as all of the resulting data fields have unique names. Data fields must have unique names because when the class structure definition is built, the tag names are included in-line at the point where the INHERITS specifier appears. Duplicate tag names will cause the structure definition to fail; it is your responsibility as a programmer to ensure that tag names are not used more than once in a structure definition.
Note: The requirement that names be unique applies only to data fields. It is perfectly legitimate (and often necessary) for subclasses to have methods with the same names as methods belonging to the superclass.
Null Objects
The Null Object is a special object reference that is guaranteed to never point at a valid object heap variable. It is used by IDL to initialize object reference variables when no other initializing value is present. It is also a convenient value to use when defining structure definitions for fields that are object references, since it avoids the need to have a pre-existing valid object reference.
Null objects are created when you call an object-creation routine but do not specify a class structure to be used as the new object’s template. The following statement creates a null object:
nullobj = OBJ_NEW()