Jump to content
  • Advertisement
Sign in to follow this  
Marius

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

This topic is 4495 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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 *).

Share this post


Link to post
Share on other sites
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);


//script
function 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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 mine
template<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 SqClassDef
template<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]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!