将Python对象转换为原生C++指针

2 投票
3 回答
2828 浏览
提问于 2025-04-15 13:58

我在考虑把Python当作嵌入式脚本语言来用在我正在做的项目上,基本上大部分功能都已经实现了。不过,我现在遇到一个问题,就是无法把一个Python扩展对象转换回原生的C++指针。

这是我的类:

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封装:

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);
}

还有Python代码:

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()

现在我可以通过以下方式正常调用前两个函数:

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]() );

但是当我尝试把Alpha类转换回它的基类(上面最后一行)时,我遇到了一个Boost错误:

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

我在网上搜索了很多,但还是搞不清楚怎么把Alpha对象转换成它的基类指针。我可以把它当作对象使用,但我更希望它能作为指针,这样一些不支持Python的代码也能使用。有没有什么建议?

3 个回答

0

我不确定这是否对你有帮助,但我之前在Lua脚本中遇到过同样的问题。我们在Lua中创建了对象,然后想用一些C++代码通过指针来处理这些对象。我们做了以下几件事:

  • 所有与对象相关的内容都是用C++写的,包括构造函数、析构函数和工厂方法;
  • Lua代码调用一个工厂方法来创建对象。这个工厂方法做了两件事:1) 给对象分配一个唯一的ID号码,2) 在C++的一个映射表中注册这个ID和对应的指针;
  • 所以,每当Lua要把一个指针传给C++代码时,它实际上是传递了一个对象的ID,然后C++代码通过这个ID在映射表中查找实际的指针。
1

这可能不是你想要的答案,但可以看看ChaiScript,它可以嵌入到你的C++应用程序中。

根据他们的网站,

ChaiScript是第一个也是唯一一个从一开始就考虑到与C++兼容的脚本语言。它是一种受ECMAScript启发的、嵌入式的类似函数的语言。

ChaiScript没有元编译器,没有库依赖,没有构建系统的要求,也没有任何遗留的负担。它可以与任何你暴露给它的C++函数无缝工作。你不需要明确告诉它任何类型,它是以函数为中心的。

使用ChaiScript,你实际上只需在你的程序中添加三行代码,就可以开始编写脚本,而完全不需要修改你的构建步骤。

2

感谢Stefan在Python和C++的邮件列表中提供的帮助,我之前漏掉了

super(Alpha, self).__init__()

在构造函数调用中,这导致父类没有被创建。我原以为这个过程会自动完成 :D

我遇到的另一个问题是,如果不把新创建的类实例保存为全局变量,它会在超出作用域后被清理掉。

现在我很开心!

撰写回答