Hello,
Yes, I encountered this situation a while ago and implemented a more generic way of implementing / extending a virtual C++ class in Squirrel. This approach has a couple of steps to it.
Say we have something like:
class EntityI {
virtual int GetHealth(){ return 0; }
virtual const char* GetName(){ return "NoNameYet"; }
// ...
};We'd like to override the virtuals in Squirrel:
class ScriptedEntityI : public EntityI {
// Do whatever to be able to route virtual function calls to most derived Squirrel
// class (for the instance).
}
The soultion has a couple of parts:
1 - A helper base class: ScriptedVirtualHelper
It does a few things (which all classes extended in this way need):
1a - Storing a reference to the C++ instance and the corresponding Squirrel instance
1b - It stores a reference to the Squirrel class for the instance
1c - It stores the last Squirrel function called (and its name):
SquirrelFunction<int> m_sf;
const SQChar* m_func;
These three are strictly not necessary but will speed up function invocation a lot,
since often two or three of them are the same from call to call.
Then it has a function:
bool SetupCall( void *pv_this, const SQChar *func );which is called before each virtual function call. It prepares everything (and does
nothing if everything is already set up right).
Finally we cast the SquirrelFunction to its right return value (from whatever type
the overridden function returns):
template<class RT>
SquirrelFunctionSafe<RT>& GetSqFn(){
return (SquirrelFunction<RT>&)m_sf;
} Now, the base class can be used to override a function in Squirrel:
class ScriptedEntityI : public EntityI, ScriptedVirtualHelper {
int ScriptedEntityI::GetHealth( ){
return SetupCall(this,_SC("GetHealth")) ?
GetSqFn<int>() () : // Get function and invoke it
0;
}
// Override other functions in the same way.
}
Then you extend ScriptedEntityI on the Squirrel side:
class SqEntityI extends ScriptedEntityI {
function GetHealth(){ return m_health }
// ... other methods
local m_health
}One key point (which is not handled by SqPlus at the moment) is to bind a C++ instance
with the same Squirrel object instance each time it is used. Otherwise in the SqEntityI above,
we would use different m_health at different calls for the same C++ object. Some way of
tracking instantiated Squirrel objects is needed, and some fast lookup scheme (C++ object
=> Squirrel object).
One must also be careful with correctly maintaing Squirrel references on the instance, the class
and the function (in ScriptedVirtualHelper).
Source for this is available through SVN:
http://trac2.assembla.com/File_Workbench/browserDirectory: trunk/FileWorkbench/script/squirrel/BindUtils.h
Regards
// ATS.