I have a C++ library with 2 classes defined in it: t_foo_base and t_foo. t_foo is derived from t_foo_base. Both of them implement a virtual function text. This function returns a string with the name of the current class. I use boost.python to generate a wrapper for this library and for this classes.
I import this library in a python script. In this script I implemented a function. This function takes one parameter and call the function "text()" on it.
Now i import this python script in a C++ application. I use boost.python again. I get the function "test_function" from the python script and call it this way:
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 );
The outpur is:
t_foo_base
t_foo
t_foo_base
t_foo_base
I would expact the 4th line of the output to be "t_foo", not "t_foo_base".
It seems, that passing a derived object by its base class pointer "cuts away" all the features of the derived object. Is there a way to do fix this problem?
I am using Visual Studio 2013, Python 3.4 and Boost 1.56.0.
This is code from the C++ library:
-- file 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" ); };
};
-- file 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 );
}
This is the python script:
import ex_three_lib
def test_function( item ):
print( item.text() )
print( "no function call here" )
This is the c++ application:
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();
}
}
}
test_functionis takingtest_fooobjects by value:test_function( *foo_ptr );Polymorphism only works if passing a pointer or reference, not a value. Since I don't know boost::python, maybe you can confirm this? - PaulMcKenzie