4.3.1.1 How it Works

This section contains technical details about SCF. If you're not
interested in details, you can skip directly to the next section which
explains how SCF should be used from the end-user's point of view.

SCF is somewhat similar to COM. This is because historically
Crystal Space initially used COM for inter-module communication. Thanks
to Dan Ogles for the initial implementation of a cross-platform COM
library; his implementation was a good test-bed for this SCF
implementation.

The differences between COM and SCF are due to the increased need for
an easier-to-use and more lightweight mechanism than COM. The COM
implementation caused some problems (because of historic bugs in EGCS
1.1.x and incompatibilities with platforms to which Crystal Space has ported).
Also it has some problems due to the native Windows types used in COM;
this experience was taken into account while developing SCF.

The main paradigm of SCF, as in COM/CORBA/Java/etc. is the
interface. You define an interface, that is, a set of abstract
methods that you want to access within some object. SCF interfaces are
plain C++ structs (or classes, it doesn't matter much except that if you're
using classes to which you will have to add the `public:' keyword).
Theoretically, interfaces can contain member variables and inline methods
(though not non-virtual methods or constructors), but this practice is
not encouraged because later someone may want to add a COM, CORBA,
etc. layer between the client and the actual object, and this will not be
possible if the interfaces contains variables, inline methods, or non-virtual
methods. If you don't plan to use COM or CORBA later, then you can
use variables and inline functions as much as you like in your own code, but
their use in Crystal Space code is highly discouraged.

Note the last method that gets a pointer of `iObjVector' type.
`iObjVector' is yet another interface. We could pass a pointer to a
`csObjVector' (the implementation of that interface) as well, but this
will mean both modules (caller and callee) should have same idea about what a
`csObjVector' is, and if it happened that you compiled the shared library
with a slightly different version of `csObjVector' (that, say, had one
member variable fewer) you will end up with a SIGSEGV crash. By instead
specifying the abstract `iObjVector', there is no need to link the
`csObjVector' class into both the caller and the callee.

Now, we put the actual implementation into a separate module (i.e. into a
shared library), and include within the client just the interface file
`idog.h'. Since the client does not have any idea how we should build
an object of the `MyDog' class, we also provide a function that will
return a newly-allocated object of that class. This is called the
class factory (in fact, a class factory is a bit more than just this,
but more about this later). Here is how to do it:

static iDog* MyDog_Create()
{
return new MyDog();
}

Okay, we did it. Now back to the client. To work with an object that
implements the `iDog' interface we need to load the shared library, get
a pointer to the MyDog_Create() function, call it and get a new
`MyDog' object. Further we work with this pointer as if it were pointing
to an `iDog' object:

Of course, you don't have to do all this stuff manually with the SCF
implementation. The SCF library provides a number of useful templates and
functions which hide these ugly implementation details from end-user.