The Communicator Audio/Telephony Server (CATS) | ||
---|---|---|
<<< Previous | Developer's Manual | Next >>> |
All classes and files in the CATS package library follow a predictable naming convention to make their development and use simpler. A class name in the CATS library, referred to generically as CatsClass, always begins with "Cats", followed by the class' functional description using distinct capitalized words. These distinct words are mapped to underscore-separated tokens in the corresponding source and header filenames of the class implementation. So, for example, the class CatsDelayLine is implemented in the source file cats_delay_line.c and header file cats_delay_line.h, respectively.
As is typical of object-oriented C, the header file associated with CatsClass includes headers of other classes referenced in the header, specifies external function prototypes, and declares a class structure that may contain data declarations, declarations of other classes, and embedded method prototypes. Referring again to the CatsDelayLine example, the corresponding header file cats_delay_line.h has the following form:
… typedef struct CatsDelayLinePrivate_str *CatsDelayLinePrivate; typedef struct CatsDelayLine_str *CatsDelayLine; CatsDelayLine CatsDelayLine_create(int bufferSize); struct CatsDelayLine_str { CatsDelayLinePrivate private; CatsDelayLine (*destroy)(CatsDelayLine this); int (*readable)(CatsDelayLine this); int (*read)(CatsDelayLine this, char *b, int off, int len); int (*write)(CatsDelayLine this, char *b, int off, int len); void (*flush)(CatsDelayLine this); int (*getBufferSize)(CatsDelayLine this); }; … |
Another common feature of all CATS package classes is the constructor CatsClass_create, which (as you might expect) creates an instance of CatsClass. We will refer to an instance of CatsClass as catsObject[1]. In addition to creating an instance, constructors are expected to perform whatever global initialization is necessary on the basis of input arguments, and to return a handle to the instance or NULL if the constructor fails.
Given an instance catsObject, note that all elements of catsObject, including methods, are accessed via standard C structure pointer dereference, e.g.
CatsDelayLine delayLine; delayLine = CatsDelayLine_create(0); delayLine->destroy(delayLine); |
Unlike object-oriented languages such as Java™ or C++, class methods in object-oriented C have the disadvantage that the object must be passed as an argument in all methods
All classes in the CATS library have a destructor, CatsClass->destroy, which takes an instance as its argument, frees memory associated with the instance, and returns NULL.
Finally, consider an implementation of a class such as CatsDelayLine through excerpts of its source file cats_delay_line.c:
… static CatsDelayLine CatsDelayLine_destroy(CatsDelayLine this); static int CatsDelayLine_readable(CatsDelayLine this); … struct CatsDelayLinePrivate_str { CatsRingBuffer buffer; }; … CatsDelayLine CatsDelayLine_create(int bufferSize) { CatsDelayLine this=NULL; if ((this = (CatsDelayLine) calloc(1,sizeof(struct CatsDelayLine_str))) != NULL) { CatsDelayLinePrivate private=NULL; char zero=0; this->destroy = CatsDelayLine_destroy; this->readable = CatsDelayLine_readable; … if ((private = this->private = (CatsDelayLinePrivate) calloc(1,sizeof(struct CatsDelayLinePrivate_str))) == NULL) return(this->destroy(this)); if ((private->buffer = CatsRingBuffer_create(bufferSize)) == NULL) return(this->destroy(this)); … return this; } static CatsDelayLine CatsDelayLine_destroy(CatsDelayLine this) { if (this->private != NULL) { CatsDelayLinePrivate private=this->private; if (private->buffer != NULL) private->buffer->destroy(private->buffer); free(this->private); } free(this); return NULL; } static int CatsDelayLine_readable(CatsDelayLine this) { return this->private->buffer->readable(this->private->buffer); } |
Note that class methods (both private and public) in the CATS package library are implemented statically according to the naming convention CatsClass_method, and public methods are assigned to the CatsClass structure's method pointers, thus ensuring that methods are only accessible through an instance of CatsClass. Note also that the private data structure is declared in the class' source file, thus preventing (as you might expect) its access outside the context of the class source file. The destructor "tears down" an instance of the class, freeing any memory allocated by the class.
As discussed earlier, interfaces comprise a special case of classes in the CATS package library. While the Java™ terminology "interface" is used to indicate that these classes contain no data of their own and are solely provided as a template to be implemented by other classes, they are in fact abstract classes since object-oriented C does not support interfaces. This distinction is clear from the context.
An example of an interface class is the CatsEventListener interface class. As the name implies, this interface provides the means for a class to register to receive event notifications from another class, without the notifying class being aware of the specific class of the listener. Consider the header file cats_event_listener.h:
… #include "cats_event.h" CatsEventListener CatsEventListener_create(void *source); struct CatsEventListener_str { CatsEventListenerPrivate private; CatsEventListener (*destroy)(CatsEventListener this); void *(*getSource)(CatsEventListener this); void (*eventGenerated)(CatsEventListener this, CatsEvent event); }; … |
In Java™ parlance, plug-in classes correspond to classes that realize interface classes - as the name implies, these interface classes allow the implementing class to be plugged in to other classes in a generic manner. The implementation of a plug-in class is best illustrated by example. Consider the following excerpt from the CatsController class, which implements a CatsEventListener instance to listen to events from a CatsCapture object it creates:
… static void CatsController_captureEventGenerated(CatsEventListener listener, CatsEvent event); … struct CatsControllerPrivate_str { … CatsEventListener captureListener; … } … CatsController CatsController_create(int argc, char **argv, CatsServer server) { … if ((capture = private->capture = CatsCapture_create(this)) == NULL) return(this->destroy(this)); … if ((private->captureListener = CatsEventListener_create(this)) == NULL) return(this->destroy(this)); private->captureListener->eventGenerated = CatsController_captureEventGenerated; capture->addListener(capture,private->captureListener); … } … static void CatsController_captureEventGenerated(CatsEventListener listener, CatsEvent event) { CatsController this=listener->getSource(listener); switch (event->eventType) { case CATS_CAPTURE_EVENT: switch(event->eventID) { case CATS_RECORD_STARTED: this->private->recordStarted = GAL_TRUE; break; case CATS_RECORD_STOPPED: this->private->recordStarted = GAL_FALSE; break; case CATS_CAPTURE_LINE_OPENED: this->private->captureLineOpen = GAL_TRUE; break; case CATS_CAPTURE_LINE_CLOSED: this->private->captureLineOpen = GAL_FALSE; break; } break; case CATS_VAD_EVENT: switch(event->eventID) { case CATS_VAD_STARTED: this->private->vadStarted = GAL_TRUE; break; case CATS_VAD_STOPPED: this->private->vadStarted = GAL_FALSE; break; } break; } } … |
Finally, it is worth noting that object-oriented C requires interface objects to be exposed by implementing classes before they can be used. When such interface objects are stored as private data, this requires the implementation of a "getter" method in the class.
[1] | As in Java™, the suggested convention of class instances is to begin their names with lower case letters, to avoid confusion with class names. |
<<< Previous | Home | Next >>> |
Developer's Manual | Up | CATS Class Reference Documentation |