sqplus 1.5 cannot instantiate abstract class (solved...)

Started by
4 comments, last by Marius 17 years, 11 months ago
Here is what I am trying to acomplish. Is there a way to export a n interface then SQClassDef<Itape>("Itape"). func(&Itape::Play,"Play");

//-----------------------------------------------------
// sound interface
class Itape
{
public:
    virtual void Play(int times, float volume)=0;
};
DECLARE_INSTANCE_TYPE(Itape);       // exported to sq
...
//-----------------------------------------------------
// sound interface system
class SndSystem
{
public:
    Itape* GetTape(const TCHAR* filename);
};
DECLARE_INSTANCE_TYPE(SndSystem); // exported to sq
...
//-----------------------------------------------------
...
// exported to sq
SQClassDef<SndSystem>("SndSystem").
    func(&System::GetTape,"GetTape");

// exported to sq </b>//error 'Itape' : cannot instantiate abstract class<b>
SQClassDef<Itape>("Itape").
    func(&Itape::Play,"Play"); 
        
...
void SndSystem::SomeFoo()
{
    SquirrelFunction<int> sf("Beep");
    sf(this);
}

//------------------------------------------------
// script
function Beep(sndsys)
{
    local tape = sndsys.GetTape();
    tape.Play(1,1.0);
}





[Edited by - Marius on June 2, 2006 11:55:44 AM]
MCO
Advertisement
SqPlus must know how to create an instance of a C++ class: abstract (containing pure virtual functions) classes/interfaces won't work.

The following will work:

class Itape{public:  virtual void Play(int times, float volume) {}};class DerivedTape : public Itape {  void Play(int times, float volume) {  // Add implementation here...  } };


Declare and bind Itape as before.

You can bind functions that take an Itape * argument (not a reference or copy), where the pointer can point to different derived classes.

You would not need to declare+bind DerivedTape and its members (or other derived classes) unless you need the ability to create instances of the specific classes (or if you want to pass such instance arguments by reference (&) or by copy (instead of by pointer (*)).

For use in script, you can create and bind C++ factories that create derived Itapes but always return the (base) interface pointer (Itape *).
I rephrase it.
In the app I see only Itapes. The implementation
of Itape is in a dll. The problem is similar
to exposing a COM iterface to script. What if I want to
script a COM object. All you see is an interface definition.

IDevice* pMouseDevice;HRESULR hr = ddx.CoCreateInstance(IID_IMouse, (void*)&pMouseDevice);...sq_engine.sq_function(pMouseDevice);//scriptfunction MouseFunction(pimouse){   pimouse.Aquire();}


So How do I expose IDevice COM interface to be
able to call methods on it from the script.

Thx again.

[Edited by - Marius on May 31, 2006 4:29:42 PM]
MCO
In this case you will have to bind stub functions:

class MyMouseDevice {  IDevice * pMouseDevice;public:  MyMouseDevice() : pMouseDevice(0) {}  bool Init(void) {    HRESULR hr = ddx.CoCreateInstance(IID_IMouse,(void*)&pMouseDevice);    if (FAILED(hr)) return false;    return true;  } // Init  void Acquire(void) {    pMouseDevice->Acquire();  } // Acquire};


Bind MyMouseDevice, MyMouseDevice::Init(), MyMouseDevice::Acquire(), etc.
That will make it.
Thx..
Regards
Marius
MCO
I dag a bit and before making wrappers and script I ...
...I find a dirty fix that alow me to expose interfaces to sq.

Here are the adds.

File: sqplus.h added code

//--------------------------------------------------------------#define SQ_DELETE_IFACE() if (up)    { unsigned char * self = (unsigned char *)up; delete[] self;}     return 0//--------------------------------------------------------------#define SQ_DECLARE_RELEASE_IFACE()   static int release(SQUserPointer up,SQInteger size) {     SQ_DELETE_IFACE();   }//--------------------------------------------------------------template<typename T>struct ConstructReleaseIface {  static int construct(HSQUIRRELVM v) {    unsigned char* pc = new unsigned char[sizeof(T)];    return PostConstruct<T>(v,(T*)pc,release);  } // construct  SQ_DECLARE_RELEASE_IFACE()};//--------------------------------------------------------------// I dont think I cover all posibilitites but I cover minetemplate<typename T>inline SquirrelObject RegisterIfaceType(HSQUIRRELVM v,const SQChar * scriptClassName,const SQChar * baseScriptClassName=0) {  int top = sq_gettop(v);  SquirrelObject newClass;  if (CreateClass(v,newClass,(SQUserPointer)ClassType<T>::type(),scriptClassName,baseScriptClassName)) {    SquirrelVM::CreateFunction(newClass,&ConstructReleaseIface<T>::construct,_T("constructor"));#ifdef SQ_USE_CLASS_INHERITANCE    // <NOTE> New member vars cannot be added to instances (OT_INSTANCE): additions must occur on the defining class (OT_CLASS), before any instances are instantiated.    if (!newClass.Exists(SQ_CLASS_OBJECT_TABLE_NAME)) { // Will always get table from most-derived registered class.      SquirrelObject objectTable = SquirrelVM::CreateTable();      newClass.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable); // Constructors must add their 'this' pointer indexed by type to this table. See PostConstruct() above.                                                                 // 11/2/05: This table will behave as a static global for each instance unless overwritten during construction (see PostConstruct() above).    } // if    SquirrelObject classHierArray;    if (!newClass.Exists(SQ_CLASS_HIER_ARRAY)) {   // Will always get table from most-derived registered class.      classHierArray = SquirrelVM::CreateArray(0); // The only constructor called will be the most-derived class: this array contains all classes in the hierarchy to be constructed.      newClass.SetValue(SQ_CLASS_HIER_ARRAY,classHierArray);    } else {      classHierArray = newClass.GetValue(SQ_CLASS_HIER_ARRAY);    } // if    classHierArray.ArrayAppend(newClass);          // Add the class to the hierarchy array. The array values will be released and replaced with UserData to free created ancestor classes.    newClass.SetValue(SQ_ANCESTOR_CLASS_INDEX,-1); // When the class hierarchy is created, this var will be used to help in recursively creating ancestor classes.#endif  } // if  sq_settop(v,top);  return newClass;} // RegisterIfaceType//---------------------------------------------------------------------// and then a dirty contructor for SqClassDeftemplate<typename TClassType>struct SQClassDef {...  SQClassDef(bool unused, const SQChar * _name,const SQChar * _base=0) : name(_name), base(_base) {    unused;    v = SquirrelVM::GetVMPtr();    newClass = RegisterIfaceType<TClassType>(v,name,base);  }...};


Here is the tste program


//------------------------------------------------------------------------class Interface{public:    Interface(){printf ("Interface::Interface \r\n");}    ~Interface(){printf ("Interface::~Interface \r\n");}    virtual void M1()=0;};class Implementor : public Interface{public:    Implementor(){printf ("Implementor::Implementor \r\n");}    ~Implementor(){printf ("Implementor::~Implementor \r\n");}    virtual void M1(){ printf ("Implementor::M2 \r\n");};};//------------------------------------------------------------------------class ClassClass{public:    ClassClass(){printf ("ClassClass::ClassClass \r\n");}    ~ClassClass(){printf ("ClassClass::~ClassClass \r\n");}    virtual void M1(){ printf ("ClassClass::M2 \r\n");}    virtual void M2(){ printf ("ClassClass::M1 \r\n");}};DECLARE_INSTANCE_TYPE(Interface)DECLARE_INSTANCE_TYPE(ClassClass)//------------------------------------------------------------------------int main(int argc, char* argv[]){    SquirrelVM::Init();    sq_setprintfunc(SquirrelVM::GetVMPtr(), printfunc); //sets the print function        try{        SquirrelObject main = SquirrelVM::CompileScript(_SC("test.nut"));        SquirrelVM::RunScript(main);        SQClassDef<Interface>(true,"Interface").                            func(&Interface::M1,"M1");               SQClassDef<ClassClass>("ClassClass").                            func(&ClassClass::M1,"M1");        SquirrelFunction<int>  proc("Main");        Implementor     impl;        ClassClass      cc2;        proc(&impl);        //proc(&impl2);        proc(&cc2);    }catch(SquirrelError& e)    {        printf(e.desc);    }    SquirrelVM::Shutdown();		return 0;}


and the script

function Main(o){    o.M1();    return 0;}


[Edited by - Marius on June 2, 2006 11:27:27 AM]
MCO

This topic is closed to new replies.

Advertisement