[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This paragraph contains technical details about SCF. If you're not interested in details, you can skip directly to the next chapter which explains how SCF should be used from the end-users' point of view.
SCF is somewhat similar to COM. This is because historically Crystal Space initially used COM for inter-module communications. Thanks to Dan Ogles for the initial implementation of a cross-platform COM library; his implementation was a good testbed for this SCF implementation.
The differences between COM and SCF are due to the increased need for an easier-to-use and maybe a more lightweight interface than COM. The COM implementation caused some problems (because of bugs in EGCS 1.1.x and incompatibilities with the Objective-C language used by NeXT). Also it has some problems due to the native Windows types used in COM; this experience has been 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 even member variables and inline methods (but no non-virtual methods and 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 were to contain variables or inline 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.
Here is an example of an interface:
struct iDog { virtual bool IsAlive() = 0; virtual char const* GetName() = 0; virtual void SetName (char const* iName) = 0; virtual void Shout(int iHowLoud) = 0; virtual void Run(int iSpeed, float iDirection) = 0; virtual bool GetChildren(iObjVector* oBrood) = 0; }; |
Note the last method that gets a pointer of iObjVector
type.
iObjVector
is yet another interface. We could pass a pointer to an
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.
Now let's write a particular implementation of the above interface.
#include "idog.h" class MyDog : public iDog { private: ... private member functions & variables ... char* Name; public: virtual bool IsAlive(); virtual char const* GetName(); virtual void SetName(char const* iName); virtual void Shout(int iHowLoud); virtual void Run(int iSpeed, float iDirection); virtual bool GetChildren(iObjVector* oBrood); ... public member functions & variables ... }; bool MyDog::IsAlive() { return true; }; char const* MyDog::GetName() { return Name; } void MyDog::SetName(char const* iName) { if (Name) free (Name); Name = strcpy (iName); } ... and so on ... |
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'. Now, since the client don't 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* Create_iDog() { 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 Create_MyDog()
function, call it and get a new
`MyDog' object. Further we work with this pointer as if it were pointing
to an `iDog' object:
handle = csFindLoadLibrary("libdog.so"); iDog (*Create_iDog)() = csGetLibrarySymbol(handle, "Create_iDog"); iDog* dog = Create_iDog(); printf("Doggy's name is %s\n", dog->GetName()); dog->Shout(100); ... |
Of course, you don't have to do all this stuff manually with current SCF implementation. The SCF library provides a number of macros and functions that almost hides the implementation details from end-user.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |