将多态对象从C ++传递给python函数

时间:2014-08-29 15:53:02

标签: python c++ python-3.x boost boost-python

我有一个C ++库,其中定义了2个类: t_foo_base t_foo 。 t_foo派生自t_foo_base。它们都实现了虚拟功能文本。此函数返回一个包含当前类名称的字符串。我使用boost.python为这个库和这个类生成一个包装器。

我在python脚本中导入这个库。在这个脚本中我实现了一个函数。该函数接受一个参数并调用函数" text()"在它上面。

现在我在C ++应用程序中导入这个python脚本。我再次使用boost.python。我得到了函数" test_function"从python脚本中调用它:

t_foo_base foo_base;
test_function( foo_base );

t_foo foo;
test_function( foo );

t_foo_base* foo_base_tpr = new t_foo_base;
test_function( *foo_base_tpr );

t_foo_base* foo_ptr = new t_foo;
test_function( *foo_ptr );

outpur是:

  

t_foo_base

     

t_foo

     

t_foo_base

     

t_foo_base

我会将输出的第4行显示为" t_foo",而不是" t_foo_base"。

看来,通过其基类指针传递派生对象"切掉了#34;派生对象的所有功能。有没有办法解决这个问题?

我正在使用Visual Studio 2013,Python 3.4和Boost 1.56.0。

这是来自C ++库的代码:

- 文件t_foo.h -

class __declspec( dllexport ) t_foo_base
{
public:
    t_foo_base(){};

    virtual ~t_foo_base(){}

    virtual std::string text( void ) const { return( "t_foo_base" ); };
};


class __declspec( dllexport ) t_foo: public t_foo_base
{
public:
    t_foo(){};

    virtual std::string text( void ) const override { return( "t_foo" ); };
};

- 文件t_foo.cpp -

#include "t_foo.h"

#include <boost/python.hpp>

using namespace boost::python;

BOOST_PYTHON_MODULE( ex_three_lib )
{
    class_< t_foo_base >( "t_foo_base" )
        .def( "text", &t_foo_base::text );
    class_< t_foo, bases< t_foo_base > >( "t_simple_callback" )
        .def( "text", &t_foo::text );
}

这是python脚本:

import ex_three_lib

def test_function( item ):
    print( item.text() )

print( "no function call here" )

这是c ++应用程序:

void
init_module_ex_three_lib
(
    void
);


boost::python::object
import_python_object( const std::string& p_name, const std::string& p_path, boost::python::api::object& p_global )
{
    using namespace boost::python;
    try
    {
        dict locals;
        locals[ "modulename" ] = p_name;
        locals[ "path" ] = p_path;
        exec
        (
            "import imp\n"
            "newmodule = imp.load_module( modulename, open( path ), path,( 'py', 'U', imp.PY_SOURCE ) )\n",
            p_global,
            locals 
        );
        return locals[ "newmodule" ];
    }
    catch( boost::python::error_already_set const & )
    {
        if( PyErr_ExceptionMatches( PyExc_ZeroDivisionError ) )
        {
            assert( false );
        }
        else
        {
            PyErr_Print();
        }
    }
}




int
main
(
void
)
{
    Py_Initialize();

    init_module_ex_three_lib();

    try
    {
        boost::python::object main_module = boost::python::import( "__main__" );
        boost::python::object main_namespace = main_module.attr( "__dict__" );

        {
            boost::python::object script = import_python_object
            (
                "ex_one_script",
                "ex_three_script.py",
                main_namespace
            );

            boost::python::object test_function = script.attr( "test_function" );

            t_foo_base foo_base;
            test_function( foo_base );

            t_foo foo;
            test_function( foo );

            t_foo_base* foo_base_tpr = new t_foo_base;
            test_function( *foo_base_tpr );

            t_foo_base* foo_ptr = new t_foo;
            test_function( *foo_ptr );
        }
    }
    catch( boost::python::error_already_set const & )
    {
        if( PyErr_ExceptionMatches( PyExc_ZeroDivisionError ) )
        {
            assert( false );
        }
        else
        {
            PyErr_Print();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您应该在这里使用boost::ref(...)。这基本上会将任何值/指针转换为它的引用。另请参阅Calling Python Functions and Methods

        t_foo_base foo_base;
        test_function( boost::ref(foo_base) );

        t_foo foo;
        test_function( boost::ref(foo) );

        t_foo_base* foo_base_tpr = new t_foo_base;
        test_function( boost::ref(*foo_base_tpr) );

        t_foo_base* foo_ptr = new t_foo;
        test_function( boost::ref(*foo_ptr) );

- &GT;

t_foo_base
t_foo
t_foo_base
t_foo