A script class cannot directly inherit from an application registered class, as the script classes are not compiled into native machine code like the application classes are.
It is however possible to emulate the inheritance by using a proxy class to hide the underlying differences in an abstract layer. The proxy class has two parts, one is the C++ side that the application sees, and the other is the script side that the scripts can see and inherit from.
The following is an example implementation of such a proxy class.
class FooScripted
{
public:
void CallMe()
{
if( !m_isDead->Get() )
{
{
ctx->
Prepare(m_obj->GetObjectType()->GetMethodByDecl(
"void CallMe()"));
}
}
}
int m_value;
static FooScripted *Factory()
{
{
ctx->
SetException(
"Invalid attempt to manually instantiate FooScript_t");
return 0;
}
return new FooScripted(obj);
}
void AddRef()
{
m_refCount++;
if( !m_isDead->Get() )
m_obj->AddRef();
}
void Release()
{
if( !m_isDead->Get() )
m_obj->Release();
if( --m_refCount == 0 ) delete this;
}
FooScripted &operator=(const FooScripted &o)
{
m_value = o.m_value;
return *this;
}
protected:
FooScripted(
asIScriptObject *obj) : m_obj(0), m_isDead(0), m_value(0), m_refCount(1)
{
m_obj = obj;
}
~FooScripted()
{
}
int m_refCount;
};
A lockable shared boolean.
Definition: angelscript.h:4306
virtual int AddRef() const =0
Adds a reference to the shared boolean.
The interface to the virtual machine.
Definition: angelscript.h:2764
virtual int SetObject(void *obj)=0
Sets the object for a class method call.
virtual void * GetThisPointer(asUINT stackLevel=0)=0
Returns a pointer to the object, if a class method is being executed.
virtual asIScriptFunction * GetFunction(asUINT stackLevel=0)=0
Returns the function at the specified callstack level.
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
virtual int SetException(const char *info, bool allowCatch=true)=0
Sets an exception, which aborts the execution.
virtual int Execute()=0
Executes the prepared function.
The engine interface.
Definition: angelscript.h:1125
virtual asIScriptContext * RequestContext()=0
Request a context.
virtual void ReturnContext(asIScriptContext *ctx)=0
Return a context when it won't be used anymore.
The interface for a script function description.
Definition: angelscript.h:4031
virtual asITypeInfo * GetObjectType() const =0
Returns the object type for class or interface method.
virtual const char * GetName() const =0
Returns the name of the function or method.
The interface for an instance of a script object.
Definition: angelscript.h:3621
virtual int Release() const =0
Decrease reference counter.
virtual asILockableSharedBool * GetWeakRefFlag() const =0
Returns the weak ref flag for the object.
virtual const char * GetName() const =0
Returns a temporary pointer to the name of the datatype.
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
This type is registered with the engine as the following:
{
}
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:305
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:311
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:705
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:773
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:708
@ asBEHAVE_FACTORY
Factory.
Definition: angelscript.h:443
@ asBEHAVE_ADDREF
AddRef.
Definition: angelscript.h:447
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:449
@ asOBJ_REF
A reference type.
Definition: angelscript.h:329
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a property for the object type.
virtual int RegisterObjectType(const char *obj, int byteSize, asQWORD flags)=0
Registers a new object type.
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
The script side is declared as shared so it can be used in all script modules. It is also declared as abstract so it cannot be instantiated by itself, only as a parent class of another script class.
This script section should preferably be included automatically by the application in all the modules that should be able to derive from the FooScripted class.
// On the script side
shared abstract class FooScripted
{
// Allow scripts to create instances
FooScripted()
{
// Create the C++ side of the proxy
@m_obj = FooScripted_t();
}
// The copy constructor performs a deep copy
FooScripted(const FooScripted &o)
{
// Create a new C++ instance and copy content
@m_obj = FooScripted_t();
m_obj = o.m_obj;
}
// Do a deep a copy of the C++ object
FooScripted &opAssign(const FooScripted &o)
{
// copy content of C++ instance
m_obj = o.m_obj;
return this;
}
// The script side forwards the call to the C++ side
void CallMe() { m_obj.CallMe(); }
// The C++ side property is exposed to the script through accessors
int m_value
{
get { return m_obj.m_value; }
set { m_obj.m_value = value; }
}
// The script class can be implicitly cast to the C++ type through the opImplCast method
FooScripted_t @opImplCast() { return m_obj; }
// Hold a reference to the C++ side of the proxy
private FooScripted_t @m_obj;
}
Now the scripts classes can derive from the FooScripted class
and access the properties and methods of the parent class normally.
// Implement a script class that derives from the application class
class FooDerived : FooScripted
{
void CallMe()
{
m_value += 1;
}
}
void main()
{
// When newly created the m_value is 0
FooDerived d;
assert( d.m_value == 0 );
// When calling the method the m_value is incremented with 1
d.CallMe();
assert( d.m_value == 1 );
}
It is of course also possible to create an instance of the scripted class from the application and access it through the FooScripted C++ proxy, thus making it transparent from the rest of the application that the implementation is actually in the script.
{
return obj2;
}
{
FooScripted *obj = CreateFooDerived(engine);
assert( obj->m_value == 0 );
obj->CallMe();
assert( obj->m_value == 1 );
obj->Release();
}
virtual void * CreateScriptObject(const asITypeInfo *type)=0
Creates an object defined by its type.
virtual int AddRef() const =0
Increase reference counter.
virtual void * GetAddressOfProperty(asUINT prop)=0
Returns a pointer to the property referenced by prop.