Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 2 - Basic Operations


Most of the classes in the MacApp class library descend from the TObject class. The TObject class defines fields and methods that provide basic functions used by many subclasses. To avoid unnecessary storage in the classes that descend from it, the TObject class defines a minimum of fields. In fact, its only fields serve as part of MacApp's RTTI support.

The methods of the TObject class enable an object to

These services are described in the following sections.

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's MA_DECLARE_CLASS macro is expanded to provide each class that uses it with a static ClassDesc field:

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 one ClassDesc field per class, not one per object.

When expanded, the MA_DECLARE_CLASS macro also defines the GetClassDescDynamic method, which returns the ClassDesc field for the class. Each class that uses MacApp's RTTI macros overrides this method to return its own ClassDesc field, so all subclasses of TObject are 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 GetClassDescDynamic directly--instead you call one of the following methods:

Gets the class ID from the ClassDesc field
Gets the class name from the ClassDesc field
Gets the class signature from the ClassDesc field
Determines whether the object descends from the class specified by the passed ClassDesc
Returns the ClassDesc field for the object's immediate superclass
Determines whether the object's ClassDesc information matches a specified ClassDesc
You can also use the MA_MEMBER and MA_DYNAMIC_CAST macros 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 the new routine, 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 Free method, or by calling the convenience routine FreeIfObject, which is described later in this section. You can call Free on any object that descends from TObject, since TObject implements a Free method.

The following describes a useful approach for initializing and freeing objects in your application, using the class TYourClass as an example:

The FreeIfObject routine calls the Free method of the passed object. The TObject::Free method calls ShallowFree, which just calls delete to delete the object from the global object heap. The delete operator 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 the Free method but doesn't necessarily call Inherited.

Creating and Deleting Objects

MacApp provides a global heap object, gObjectHeap, to allocate memory for objects your application creates with the global new operator. The TObject class overrides operator new and operator delete to work with MacApp's global heap object. The operator new routine calls MacApp's MAOperatorNew routine, which in turn calls gObjectHeap->Allocate. The operator delete routine calls the MAOperatorDelete routine, which in turn calls gObjectHeap->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 TObject class supplies dependency support for all its subclasses, and works with the global dependency object, gMacAppDependencies, to support MacApp's dependency mechanism. The following TObject methods take part in dependency operations:

Calls the global dependency space's AddDependency method to make the passed object a dependent of the current object
Results in a call to DoUpdate for each dependent object (you call an object's Changed method when a change has occurred that should be reported to the object's dependents)
Called when a notifier of the current object changes; DoUpdate does nothing in TObject--subclasses add specific updating behavior
Accessor for the global dependency object, gMacAppDependencies
Calls the global dependency space's RemoveDependency method to remove the passed object as a dependent of the current object
Calls the global dependency space's RemoveDependencies method to remove any dependency relationships based on the current object; RemoveAllDependencies is called by the TObject::Free method if RemoveDependenciesOnFree returns TRUE
Returns TRUE in TObject, indicating that any dependency relationships that include this object should be removed when the object is freed
You can read more about these methods in the MacApp Class and Method Reference.

Reading and Writing Streams

MacApp provides stream classes that are useful for transferring data between a variety of destinations, including files, memory, and resources.

The TObject class provides methods for reading and writing stream data. Any subclass of TObject can override the WriteTo method to write its data to a stream, and the ReadFrom method 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 the Clone method, which is implemented in TObject. 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, the TObject::Clone method calls TObject::ShallowClone, which simply allocates a block of memory the size of the current object and uses the Toolbox BlockMove routine to copy the current object's data into the new object.

Classes that allocate memory or do any special handling need to override the Clone method. Typically, an override of Clone calls Inherited::Clone and 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 TDrawingEnvironment object. You might want all the shapes drawn in that environment to refer to the same TDrawingEnvironment object, 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 Clone method 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 the Clone method in your class.

Use of the Clone method may not be optimal for duplicating objects of type TDocument or its subclasses. You might instead call the application object's DoMakeDocument method 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

The TObject class provides several methods to test for object equality and inequality. The IsSame method compares the object to the passed object reference and returns TRUE if the object references match.

The CompareObject method and all of the TObject class operator comparison methods (operator!=, operator<, operator<=, operator==, operator>, and operator>=) call the IsLessThan, IsGreaterThan, and IsEqual methods to compare the object to the passed object reference. The IsLessThan, IsEqual, and IsGreaterThan methods do nothing in TObject, so you must override them if you wish to use them or to use CompareObject or the operator comparison methods.

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

The SubClassResponsibility method 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. The SubClassResponsibility method reports only in debug versions of the application--otherwise it does nothing.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996