Question

I notice that Swig provides a whole host of functions to allow for typecasting objects to their parent classes. However, in C++ one can produce a function like the following:

A * getAnObject()
{
  if(someBoolean)
    return (A *) new B;
  else
    return (A *) new C;
}

Where "A" is the parent of classes "B" and "C". One can then typecast the pointer returned into being a "B" type or "C" type at one's convenience like:

B * some_var = (B *) getAnObject();

Is there some way I can typecast an object I've received from a generic-pointer-producing function at run-time in the scripting language using the wrappers? (In my case, Lua?) I have a function that could produce one of about a hundred possible classes, and I'd like to avoid writing an enormous switch structure that I'd have to maintain in C++. At the point where I receive the generic pointer, I also have a string representation of the data type I'd like to cast it to.

Any thoughts? Thanks!

-- EDIT --

I notice that SWIG offers to generate copy constructors for all of my classes. If I had it generate those, could I do something like the following?:

var = myModule.getAnObject(); -- Function that returns an object type-cast down to a pointer of the parent class, as in the function getAnObject() above.
var = myModule.ClassThatExtendsBaseClass(var); -- A copy constructor that SWIG theoretically creates for me

and have var then be an instance of the inheriting class that knows it's an instance of the inheriting class?

Was it helpful?

Solution

I developed a solution to my problem. I'm new to lua's garbage collection, so I'm not sure if it's memory-leak-proof, but it does what I need it to do. (It's also not fool-proof -- if you pass a valid data type and an object that shouldn't be cast as that data type, bad stuff will result.)

=================================================================================

static int lua_typecast_Object_I(lua_State *L)
{
        void * myDataPtr;
        void ** ptrToPtr = &myDataPtr;

        // Attempt to convert the first parameter to a pointer of
        // the lowest parent type from which all other data types 
        // inherit. e.g. "Object_I"

        if (!SWIG_IsOK(SWIG_ConvertPtr(L, 1, ptrToPtr, SWIGTYPE_p_Namespace1__Object_I, 0)))
        {
                lua_pushnumber(L, -1);
                lua_pushstring(L,"Pointer conversion in typecast function failed.");
                return 2;
        }

        const char * type_name = luaL_checkstring(L, 2);

        // Search the SWIG module for a swig_type_info that contains the data
        // type string that was passed as the second parameter

        swig_module_info* module=SWIG_GetModule(L);
        swig_type_info *type = SWIG_TypeQueryModule(module,module,type_name);
        if(type == NULL)
        {
                lua_pushnumber(L, -2);
                lua_pushstring(L,"Failed to find swig_type_info for specified type.");
                return 2;
        }

        // Using the swig_type_info that we found, create a new object on 
        // the stack of the desired data type and return.

        SWIG_Lua_NewPointerObj(L, myDataPtr, type, 0);
        return 1;
}

=================================================================================

Hope that helps someone!

OTHER TIPS

I solved this using a typemap and a class field that holds the SWIG structure swig_type_info of the class type.

For example. Suppose you have a BaseClass that contains basic linked list functionality, yet the actual nodes can be any class derived from BaseClass. Thus you have a polymorphic linked list. In the base class I define a value "stored_swig_info" that holds the result of the call to SWIG_TypeQuery(..). I set this value during initialization. Then at runtime you can use the following:

// The typemap converts a function result from C->Lua. 
%typemap(out) BaseClass* {
   // stored_swig_info is set by calling SWIG_TypeQuery("DerivedClass *"), done at
   // initialization, so it can be used here to read the actual type
   swig_type_info* info = $1->stored_swig_info;
   SWIG_NewPointerObj(L, $1, info, 0); SWIG_arg++;
};

// base class
class BaseClass {
private:
  swig_type_info *stored_swig_info;
public:
  BaseClass* next () { ... };
  BaseClass* prev () { ... };
};

// derived class
class DerivedClass: public BaseClass {
};

And in the actual class modules the constructor does the following:

BaseClass::BaseClass () {
  ...
  stored_swig_info = SWIG_TypeQuery("BaseClass *");
  ...
}

...

DerivedClass::DerivedClass () {
  ...
  stored_swig_info = SWIG_TypeQuery("DerivedClass *");
  ...
}

A note on the implementation. Make sure this initialization is called after the lua module is initialized or else the SWIG typetabel is not yet filled.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top