[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.4.1.2 Using SCF

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.

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()

This function should be called each time you get a new reference to a object and store it for a long-time usage. Rather than invoking this method manually, you can use a smart-pointer to automate reference counting (see section Correctly Using Smart Pointers).

void DecRef()

Call this function to decrement the object's reference count. When the reference count reaches zero, the object is deleted automatically, provided that it is not an interface embedded within another object, SCF Embedded Interfaces. There should be one matching DecRef() for each IncRef() invocation.

void AddRefOwner(iBase**)

Call this function to set up a weak reference to the object . A weak reference is one which is invalidated automatically when the referenced object is destroyed. This is useful in cases when some object wants to hold a pointer to an SCF object without actually owning a reference to the SCF object. Owning a reference prevents the SCF object from being destroyed, whereas holding a weak reference merely says that you are interested in this object as long as it is alive, but that you don't want to forcibly keep it alive. The argument to this method is a pointer to a variable which can hold a pointer to an SCF object. Rather than invoking this method manually, you typically would use a weak-reference template to automate the reference management (`CS/include/csutil/weakref.h').

void RemoveRefOwner(iBase**)

Call this function to remove a weak reference to the object.

iBase* QueryInterface(scfInterfaceID InterfaceID, int Version); This

method will return a pointer to an interface or to an embedded interface, (see SCF Embedded Interfaces). The Interface ID is synonymous to the name of the interface. In previous versions of SCF this method used to accept a string containing the name of the interface. This has been replaced by the ID for performance reasons. You can get the ID of an interface by invoking 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 ] [ >> ]

This document was generated using texi2html 1.76.