python object to native c++ pointer

2019-02-15 18:55发布

问题:

Im toying around with the idea to use python as an embedded scripting language for a project im working on and have got most things working. However i cant seem to be able to convert a python extended object back into a native c++ pointer.

So this is my class:

class CGEGameModeBase
{
public:
    virtual void FunctionCall()=0;
    virtual const char* StringReturn()=0;
};

class CGEPYGameMode : public CGEGameModeBase, public boost::python::wrapper<CGEPYGameMode>
{
public:
    virtual void FunctionCall()
    {
        if (override f = this->get_override("FunctionCall"))
            f();
    }

    virtual const char* StringReturn()
    {
        if (override f = this->get_override("StringReturn"))
            return f();

        return "FAILED TO CALL";
    }
};

Boost wrapping:

BOOST_PYTHON_MODULE(GEGameMode)
{
    class_<CGEGameModeBase, boost::noncopyable>("CGEGameModeBase", no_init);

    class_<CGEPYGameMode, bases<CGEGameModeBase> >("CGEPYGameMode", no_init)
        .def("FunctionCall", &CGEPYGameMode::FunctionCall)
        .def("StringReturn", &CGEPYGameMode::StringReturn);
}

and the python code:

import GEGameMode

def Ident():
    return "Alpha"

def NewGamePlay():
    return "NewAlpha"


def NewAlpha():
    import GEGameMode
    import GEUtil

    class Alpha(GEGameMode.CGEPYGameMode):
        def __init__(self):
            print "Made new Alpha!"

        def FunctionCall(self):
            GEUtil.Msg("This is function test Alpha!")

        def StringReturn(self):
            return "This is return test Alpha!"

    return Alpha()

Now i can call the first to functions fine by doing this:

const char* ident = extract< const char* >( GetLocalDict()["Ident"]() );
const char* newgameplay = extract< const char* >( GetLocalDict()["NewGamePlay"]() );

printf("Loading Script: %s\n", ident);
CGEPYGameMode* m_pGameMode = extract< CGEPYGameMode* >( GetLocalDict()[newgameplay]() );

However when i try and convert the Alpha class back to its base class (last line above) i get an boost error:

TypeError: No registered converter was able to extract a C++ pointer to type class CGEPYGameMode from this Python object of type Alpha

I have done alot of searching on the net but cant work out how to convert the Alpha object into its base class pointer. I could leave it as an object but rather have it as a pointer so some non python aware code can use it. Any ideas?

回答1:

Thanks to Stefan from the python c++ mailling list, i was missing

super(Alpha, self).__init__()

from the constructor call meaning it never made the parent class. Thought this would of been automatic :D

Only other issue i had was saving the new class instance as a global var otherwise it got cleaned up as it went out of scope.

So happy now



回答2:

Well, I am not sure whether it will help you, but I had the same problem with scripts in Lua. We created objects from Lua and wanted some c++ code to handle the objects via pointers. We did the following:

  • all object stuff was written in c++, including constructors, destructors and factory method;
  • lua code was calling a factory method to create an object. this factory method 1) gave the object a unique ID number and 2) registered it in the c++ map, that mapped ID numbers to native pointers;
  • so, whenever lua was going to pass a pointer to c++ code, it gave an object ID instead, and the c++ code looked up the map for finding the actual pointer by ID.


回答3:

May not be the answer you are looking for, but take a look at ChaiScript for embedding in your C++ application.

According to their website,

ChaiScript is the first and only scripting language designed from the ground up with C++ compatibility in mind. It is an ECMAScript-inspired, embedded functional-like language.

ChaiScript has no meta-compiler, no library dependencies, no build system requirements and no legacy baggage of any kind. At can work seamlessly with any C++ functions you expose to it. It does not have to be told explicitly about any type, it is function centric.

With ChaiScript you can literally begin scripting your application by adding three lines of code to your program and not modifying your build steps at all.