Important: The information in this document is obsolete and should not be used for new development.
TObject
Most of the classes in the MacApp class library descend from theTObjectclass. TheTObjectclass defines fields and methods that provide basic functions used by many subclasses. To avoid unnecessary storage in the classes that descend from it, theTObjectclass defines a minimum of fields. In fact, its only fields serve as part of MacApp's RTTI support.The methods of the
TObjectclass enable an object to
These services are described in the following sections.
- provide RTTI information about its class hierarchy
- initialize and free its data
- create and delete objects
- register as a dependent of another object and be notified of changes in the objects on which it depends
- write its data to, or read its data from, a stream destination of any type (a file stream, a handle stream, and so on)
- create a copy of itself
- compare itself to another object
- identify an operation that must be supplied by a subclass
RTTI Fields and Methods
MacApp supplies a number of macro definitions to make runtime type information available to your application, as described in "Runtime Type Information," beginning on page 27. MacApp'sMA_DECLARE_CLASSmacro is expanded to provide each class that uses it with a staticClassDescfield:
static const ClassDesc fgClassDesc;Because the field is static (that is, one variable per class is instantiated, initialized at static init time, and accessed through the field), MacApp's RTTI support inserts just oneClassDescfield per class, not one per object.When expanded, the
MA_DECLARE_CLASSmacro also defines theGetClassDescDynamicmethod, which returns theClassDescfield for the class. Each class that uses MacApp's RTTI macros overrides this method to return its ownClassDescfield, so all subclasses ofTObjectare compatible for RTTI. This is important for operations such as determining whether an object belongs in a list of objects of a specific type.You don't normally call
GetClassDescDynamicdirectly--instead you call one of the following methods:
You can also use the
GetClassID- Gets the class ID from the
ClassDescfieldGetClassName- Gets the class name from the
ClassDescfieldGetStandardSignature- Gets the class signature from the
ClassDescfieldDescendsFrom- Determines whether the object descends from the class specified by the passed
ClassDescGetSuperClass- Returns the
ClassDescfield for the object's immediate superclassIsSameClass- Determines whether the object's
ClassDescinformation matches a specifiedClassDescMA_MEMBERandMA_DYNAMIC_CASTmacros to access RTTI information, as shown in the following code fragment:
if (MA_MEMBER(theControl, TPopup)) ...; // Do something that requires theControl to descend from TPopup. MMailable* mailDoc = MA_DYNAMIC_CAST(MMailable, fDocument); if (!mailDoc) Failure(minErr, 0); // "...program error" if the document // can't be cast to the desired type.Initializing and Freeing Objects
MacApp uses a two-phase process for initializing objects. When you create a new object with thenewroutine, the first phase of initialization takes place automatically--the object's constructor routines are called (one for each class in the object's class hierarchy that has a constructor). Then you perform the second phase by calling the object's initialization method. An object's initialization method typically calls the initialization method of its parent object, and so on, up the class hierarchy. MacApp uses this two-phase initialization for objects it creates as well.You free an object by calling its
Freemethod, or by calling the convenience routineFreeIfObject, which is described later in this section. You can callFreeon any object that descends fromTObject, sinceTObjectimplements aFreemethod.The following describes a useful approach for initializing and freeing objects in your application, using the class
TYourClassas an example:
The
- When you define a class, supply it with a constructor routine that has the same name as the class itself (
TYourClass). In the constructor, set fields of the object to default or safe values (such asNULL). Don't do anything in the constructor that might fail, such as allocating memory--if a failure occurs in a constructor, the object may still have uninitialized references that make it unsafe to delete. That's why MacApp provides a two-phase initialization. (MacApp's failure mechanism is described in Chapter 3, "Core Technologies.")- If your class requires additional initialization, supply an initialization method. By convention, initialization methods start with an
I, such asIYourClass. If the parent class ofTYourClasshas an initialization method, you normally call it fromIYourClass, often as the first action. In theIYourClassmethod, do any memory allocation or other initialization that can't be safely done in the constructor routine.If
IYourClassdoes anything that may fail, put failure handling in a wrapper routine that creates an instance of your object and calls the initialization method. If a failure occurs, your destructor routine (described in the next item) will free the memory from any successful memory allocations; if it is appropriate to free the object itself, the wrapper routine can do so, using theFreeIfObjectroutine.- Supply your object with a destructor routine,
~TYourClass. A destructor method frees any memory allocated in the initialization method and performs any other necessary cleanup. It has the same name as the class, preceded by a tilde symbol (~), and is called automatically whenever an instance of the class is freed with thedeleteroutine. Don't call any failure methods in the constructor. Use theFreeIfObjectroutine to free any objects allocated byTYourClass.
FreeIfObjectroutine calls theFreemethod of the passed object. TheTObject::Freemethod callsShallowFree, which just callsdeleteto delete the object from the global object heap. Thedeleteoperator is described in the next section.Your application may wish to prevent an object from being automatically freed when it is deleted. For example, you may be keeping track of references to an object and want to delete the object only when the reference count is zero. To prevent automatic freeing of a deleted object, you can imitate the MacApp class
TDeskScrapView, which overrides theFreemethod but doesn't necessarily callInherited.Creating and Deleting Objects
MacApp provides a global heap object,gObjectHeap, to allocate memory for objects your application creates with the globalnewoperator. TheTObjectclass overridesoperatornewandoperatordeleteto work with MacApp's global heap object. Theoperatornewroutine calls MacApp'sMAOperatorNewroutine, which in turn callsgObjectHeap->Allocate. Theoperatordeleteroutine calls theMAOperatorDeleteroutine, which in turn callsgObjectHeap->Free.The global heap object is described in more detail in Chapter 3, "Core Technologies."
Dependency Relationships
MacApp implements a system for managing dependency relationships between objects. It allows an object to be registered as a dependent of another object and to be notified of changes in the object on which it depends. MacApp's dependency system is described in detail in Chapter 3, "Core Technologies."The
TObjectclass supplies dependency support for all its subclasses, and works with the global dependency object,gMacAppDependencies, to support MacApp's dependency mechanism. The followingTObjectmethods take part in dependency operations:
You can read more about these methods in the MacApp Class and Method Reference.
AddDependent- Calls the global dependency space's
AddDependencymethod to make the passed object a dependent of the current objectChanged- Results in a call to
DoUpdatefor each dependent object (you call an object'sChangedmethod when a change has occurred that should be reported to the object's dependents)DoUpdate- Called when a notifier of the current object changes;
DoUpdatedoes nothing inTObject--subclasses add specific updating behaviorGetDependencySpace- Accessor for the global dependency object,
gMacAppDependenciesRemoveDependent- Calls the global dependency space's
RemoveDependencymethod to remove the passed object as a dependent of the current objectRemoveAllDependencies- Calls the global dependency space's
RemoveDependenciesmethod to remove any dependency relationships based on the current object;RemoveAllDependenciesis called by theTObject::Freemethod ifRemoveDependenciesOnFreereturnsTRUERemoveDependenciesOnFree- Returns
TRUEinTObject, indicating that any dependency relationships that include this object should be removed when the object is freedReading and Writing Streams
MacApp provides stream classes that are useful for transferring data between a variety of destinations, including files, memory, and resources.The
TObjectclass provides methods for reading and writing stream data. Any subclass ofTObjectcan override theWriteTomethod to write its data to a stream, and theReadFrommethod to read its data from a stream. MacApp's document classes use streams to write their data to disk.MacApp's streaming mechanism is described in detail in Chapter 3, "Core Technologies."
Cloning Objects
You can create a new object by copying an existing object with theClonemethod, which is implemented inTObject. Cloning produces an object whose fields have the same values as the original object. It can be an efficient way of duplicating an object without having to copy its values field by field.Implementation of Cloning
To implement cloning, theTObject::Clonemethod callsTObject::ShallowClone, which simply allocates a block of memory the size of the current object and uses the ToolboxBlockMoveroutine to copy the current object's data into the new object.Classes that allocate memory or do any special handling need to override the
Clonemethod. Typically, an override ofClonecallsInherited::Cloneand casts the returned object to the type of the current class. It then clones any owned objects, sets up any special relationships, and does any other task that can't be handled by simply copying the original object.Complications of Cloning
Cloning can become complicated when the cloned object refers to another object. For example, should the referred-to object also be cloned? Or should the new object point to the same object the original object does? The answer can vary, depending on how the object reference is used.Suppose, for example, you are cloning an object that has a reference to another object, and the referenced object logs an entry whenever the main object is accessed. You probably want to clone the log object as well, to keep a separate log for the new main object. You may also want to clear the log for the cloned object.
But suppose you are cloning an object that has a reference to a database object. Chances are you don't want to duplicate an entire database--you just want the original object and the new object to refer to the same database.
In still another case, suppose you are cloning a shape object that has a reference to a
TDrawingEnvironmentobject. You might want all the shapes drawn in that environment to refer to the sameTDrawingEnvironmentobject, or you might have reasons for keeping a separate copy with each shape.You should consider these issues when cloning an object in your application. By default, the
Clonemethod copies the original object exactly, so all references in the new object will point to the same items as the corresponding references in the cloned object. If this is not the desired behavior, you must change it by overriding theClonemethod in your class.
- Note
- Use of the
Clonemethod may not be optimal for duplicating objects of typeTDocumentor its subclasses. You might instead call the application object'sDoMakeDocumentmethod to create a new document, then call a custom document-cloning method to copy specific information from the cloned document to the new document.![]()
Comparing Objects
TheTObjectclass provides several methods to test for object equality and inequality. TheIsSamemethod compares the object to the passed object reference and returnsTRUEif the object references match.The
CompareObjectmethod and all of theTObjectclass operator comparison methods (operator!=,operator<,operator<=,operator==,operator>, andoperator>=) call theIsLessThan,IsGreaterThan, andIsEqualmethods to compare the object to the passed object reference. TheIsLessThan,IsEqual, andIsGreaterThanmethods do nothing inTObject, so you must override them if you wish to use them or to useCompareObjector the operator comparison methods.
- Note
- Except for determining that two objects with the same numerical reference value are the same object, MacApp makes no definition of what object equality or inequality means. If you override MacApp's operator comparison methods, you should define these terms to have meaning in your application.
![]()
The SubClassResponsibility Method
TheSubClassResponsibilitymethod reports that a method was called that should have been overridden by a subclass. This method can be useful during development as a reminder that a routine has not yet been implemented. TheSubClassResponsibilitymethod reports only in debug versions of the application--otherwise it does nothing.