[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The only include header file you need to include to utilize SCF functionality is `scf.h'. It contains a number of macros and functions that you will need for easier use of SCF. If you plan to use SCF in your own project without utilizing Crystal Space, you will also need to include `scf.cpp' in your main application, and `scfimp.cpp' in both your main application and each plugin module. However, projects based upon Crystal Space can simply link with the `csutil' library which contains the SCF implementation.
Much basic functionality of SCF is provided by a central object. It can
be accessed as `iSCF::SCF' and is of type `iSCF*' (which is also a
valid SCF interface). This object is global and can be accessed from
anywhere, even from dynamic libraries (plugin modules). It is used by
several parts of SCF. Note that this object is only available after
calling scfInitialize()
, the main initialization function of SCF.
In typical use, howerver, you rarely need to interact directly with
`iSCF::SCF'. Instead, you invoke several convenient SCF macros which
interact with `iSCF::SCF' on your behalf.
All SCF classes should be derived from the basic interface `iBase'. This interface declares the bare minimum set of methods which all SCF classes should provide:
void IncRef()
void DecRef()
DecRef()
for each
IncRef()
invocation.
void AddRefOwner(iBase**)
void RemoveRefOwner(iBase**)
iBase* QueryInterface(scfInterfaceID InterfaceID, int Version); This
iSCF::SCF->GetInterfaceID(name)
.
To simplify things even further, `scf.h' provides several macros that
provide default declarations and default implementations of these
methods. The `SCF_DECLARE_IBASE' macro will declare these methods
within any class definition that is derived from `iBase'. The
SCF_IMPLEMENT_IBASE()
macro will add the default implementation of these
methods to your module. Finally, the SCF_IMPLEMENT_FACTORY()
macro will
implement the factory function for your class which returns new instances of
the class to callers.
Example:
// Abstract interface file (itest.h) struct iTest : public iBase { ... }; // Concrete implementation header (test.h) class Test : public iTest { public: SCF_DECLARE_IBASE; }; // Concrete implementation source (test.cpp) SCF_IMPLEMENT_FACTORY(Test) SCF_IMPLEMENT_IBASE(Test) |
In reality, we need a few more macros because the QueryInterface()
function is not static--it depends upon the interfaces implemented by given
object. In fact, SCF_IMPLEMENT_IBASE()
defines IncRef()
,
DecRef()
, AddRefOwner()
, RemoveRefOwner()
, and the
beginning of the QueryInterface()
function, but not the end of that
function (i.e. the closing brace). That's because you have to use an
additional macro called SCF_IMPLEMENTS_INTERFACE()
which will add the
code required to support all implemented interface inside
QueryInterface()
:
SCF_IMPLEMENT_FACTORY(Test) SCF_IMPLEMENT_IBASE(Test) SCF_IMPLEMENTS_INTERFACE(iTest) SCF_IMPLEMENT_IBASE_END |
The SCF_DECLARE_IBASE()
macro also defines a few member variables:
`scfRefCount', `scfWeakRefOwners', and `scfParent'.
`scfRefCount' is the accumulator for external references to this object
and is used by IncRef()
and DecRef()
methods.
scfWeakRefOwners
maintains the list of weak reference owners, if any.
The `scfParent' variable points to the parent object, if any, and is also
used by IncRef()
and DecRef()
. Objects are chained together in a
tree-like fashion, and an call to IncRef()
will also call
scfParent->IncRef()
; same with DecRef()
. The root of the chain
is the class factory, that is, an object that is used to create objects of a
specific class. The object tree looks like this:
ClassFactory => Object => Embedded interface => Embedded interface => Sub-embedded interface |
Thus, if we call the IncRef()
method for Sub-embedded interface,
we also will increment reference count for Object and
ClassFactory.
You also should call SCF_CONSTRUCT_IBASE(parent)
inside your class
constructor, this macro will initialize `scfRefCount' to zero and
`scfParent' to parent. The constructor of many SCF classes
should receive at least one argument of type `iBase*', which it should
pass along to the SCF_CONSTRUCT_IBASE()
macro. It is also valid to
specify `NULL' as the parent if the instance should have no parent.
Likewise, you should call SCF_DESTRUCT_IBASE()
inside your class
destructor. This will reverse the initialization performed by the
corresponding SCF_CONSTRUCT_IBASE()
invocation.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |