There is a basic class type called taBase that uses the TypeAccess
type information to perform a number of special functions automatically.
This object is aware of its own type information, and can thus save and
load itself, etc. Special code has been written in both the TypeAccess
system and in CSS that takes advantage of the interface provided by the
taBase type. Thus, it is recommended that user's derive all of
their types from this base type, and use special macros to provide
derived types with the hooks necessary to get their own type information
and use it effectively. The type TAPtr is a typedef
for a
pointer to a taBase object. The definition of a taBase object
and the macros that are used with it are all in `ta/ta_base.h'.
All taBase objects have only one member, which is a reference
counter. This provides a mechanism for determining when it is safe to
delete an object when the object is being referenced or pointed to in
various different places. taBase provides a set of referencing and
pointer-management functions that simplify the use of a reference-count
based memory management system. Ref
increments the reference
count, unRef
decrements it, Done
checks if the refcount is
zero, and deletes the object if it is, and unRefDone
does both.
Own
both Ref's an object and sets its owner. For pointers,
SetPointer
unrefs any existing object that the pointer points to,
and sets it to point to the new object. DelPointer
does an
unRefDone
on the object pointed to, and sets the pointer to NULL.
OwnPointer
is like SetPointer except it also sets the owner of
the pointed-to object to the one given by the argument. See
section 17.8.1 Basic Functions and `ta/ta_base.h' for more details.
The one essential function that taBase provides is
GetTypeDef()
, which is a virtual function that returns a pointer
to the TypeDef
type descriptor for this object. This function is
defined as part of the basic macro TA_BASEFUNS
, which must be
included in all classes derived from taBase. This function makes it
possible for a generic pointer to a taBase object to find out what type
of object is really being pointed to.
There are a number of functions defined on the taBase type that simply
call the corresponding function on the TypeDef pointer. These can
be found in the `ta/ta_base.h' header file. They just make it
easier to call these commonly-used functions, instead of requiring the
user to put in a GetTypeDef
function in between.
taBase also provides a simplified way of managing the construction,
deletion, and copying of an object. Basically, construction is broken
down into a set of functions that Initialize
the member
variables, Register
the new token with the type if it is keeping
track of tokens, and it sets the default name of the object based on its
type name using SetDefaultName
. The TA_BASEFUNS
macro
defines a default constructor that calls these three functions in that
order. The user thus needs to provide a Initialize
function for
every class defined, which does the appropriate member initialization.
Note that if this function is not defined, the one on the parent class
will be called twice, so its more efficient to include a blank
Initialize function when there are no members that need to be
initialized.
The destructor function is similar to the constructor. A default
destructor is defined in TA_BASEFUNS
, which simply calls
unRegister
, and Destroy
. Thus, the user needs to provide
a Destroy
function which frees any additional resources allocated
by the object, etc. Like Initialize
, a blank Destroy
should be defined when there is nothing that needs to be done to prevent
the parent function from being called twice.
Copying, cloning, and making a new token of the given type are also
supported in the taBase class. The Copy
function performs
the basic copy operations for both the copy constructor and the =
operator. This should replace the values of this class and any of its
existing sub-objects with those of the object passed to it, as it is
intended for assignment between two existing objects. In general, the
=
operator should be used for copying all members, except for the
case of LINK_GROUP
groups and lists, which should use the
BorrowUnique
function (since they do not own the items in the list,
just link them). Copy
must call the parent's Copy
function as well. As a minor simplification of calling the parent (and
to provide a copy function for just the items in a given class), it is
conventional to define a Copy_
function, which does everything
except for calling the parent copy function. The macro COPY_FUNS
can be used to define a Copy
function which calls the parent
function and then Copy_
. The macro SIMPLE_COPY
defines a
Copy_
function which uses the type-scanned information to do the
copying. It is slower than hand-coding things, so it probably shouldn't
be used on types which will have a lot of tokens or be copied often.
A Clone
function which returns a TAPtr
to a new duplicate
of this object is defined in TA_BASEFUNS
, as well as an "unsafe"
version of Copy
(UnSafeCopy
), which takes a generic
TAPtr
argument and casts it into their type. The argument's type
should thus be tested before calling this function. A safe interface to
this function is provided by the CopyFrom
function, which does
the type checking. Finally, the MakeToken
function will create a
new token of the type.
The taBase class also contains functions for creating and manipulating a structure hierarchy of objects. This is where certain objects contain groups of other objects, which contain other objects, etc. For example, the PDP++ software has a structure hierarchy built around a root object, which contains projects, which contain lots of other objects like networks, projects, environments, etc. Special container objects like taList and taGroup play an important role in representing and manipulating this structure (note that it is possible to write other types of container objects which could play the same role simply by overloading the same functions that these objects do).
When an object is "linked" into the object hierarchy, a function called
InitLinks
is called. This function should perform any kind of
initialization that depends on the object being situated in the
hierarchy, like being able to know what object "owns" this one.
taBase has functions for getting and setting the owner of an object.
For example, when a group (taList or taGroup creates a new
object and links it into its list of objects, it calls the
SetOwner
function with a pointer to itself on this new object,
and then it calls InitLinks
. Similarly, when the object is
removed from the group, the CutLinks
function is called, which
should cut any links that the object has with other objects.
An object's location in the object hierarchy can be represented by a
path to that object from a global root object. A given
application is assumed to have a root object, which contains all other
objects. A pointer to that object is kept in tabMisc::root, which
is used to anchor the path to any given object. An object can find its
path with the GetPath
function, and an object can be found from a
path with the FindFromPath
function.
Finally, a function for allowing an object to set the values of certain
members based on changes that might have been made in other members
after a user edits the object, called UpdateAfterEdit
, is
provided. This function is called on most objects after they are loaded
from a save file (except those with the #NO_UPDATE_AFTER
comment
directive), and on all objects after the user hits Apply or Ok
in an edit dialog, and after any member is set through a CSS assign
statement. While the object does not know which members were changed
when UpdateAfterEdit
is called, the object can buffer previous
state on its own to figure this out if it is needed.
For a step-by-step guide to making a new class that derives from taBase, see section 17.4 Coding Conventions and Standards.