views:

431

answers:

1

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?

+2  A: 

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!

Zack
The usual Lua convention for error returns is to return nil, "message" where you are returning a numeric code and a message. Returning nil turns out to be really easy to distinguish from any other "valid" return value on the Lua side, hence the idiom. Its also the pattern followed by many of the core modules. Alternatively, you might consider using luaL_error() instead since any error in type naming is likely a serious problem. See http://www.lua.org/manual/5.1/manual.html#luaL_error for the details.
RBerteig
I don't spot any leaks offhand, but don't feel versed enough in the SWIG internals to certify that ;-)
RBerteig