[C++-sig] Converting base type to derived type when returning to Python
Albert Strasheim
fullung at gmail.com
Tue Jan 16 00:16:47 CET 2007
Hello Roman/all
I think the problem I'm running into is that the library I'm trying to
wrap returns something that is derived from something that is derived
from Message. The interface I'm trying to wrap exists exactly to hide
these details. For the ActiveMQ C++ library I have all the sources
available, but a commercial library built on top of the CMS interface
might not expose its internal classes.
Here's a simplified code snippet to show the problem I'm having.
First, a setup.py to build on Linux:
from distutils.core import setup
from distutils.extension import Extension
files = ['messaging.cpp']
setup(name='messaging',
ext_modules=[
Extension('messaging', ['messaging.cpp'],
library_dirs=[],
libraries=['boost_python'],
include_dirs=[],
depends=[]),
])
The source:
#include <boost/python.hpp>
using namespace boost::python;
#define TEXTMESSAGE_IS_INTERFACE 0
struct Message{virtual ~Message(){}};
#if TEXTMESSAGE_IS_INTERFACE
struct TextMessage : public Message{
virtual ~TextMessage(){}
virtual std::string getText() const = 0;};
struct TextMessageImpl : public TextMessage{
virtual ~TextMessageImpl(){}
virtual std::string getText() const{return "hello";}};
#else
struct TextMessage : public Message{
virtual ~TextMessage(){}
virtual std::string getText() const{return "hello";}};
#endif
struct MessageConsumer{
Message* receive(){
#if TEXTMESSAGE_IS_INTERFACE
return new TextMessageImpl();
#else
return new TextMessage();
#endif
}};
BOOST_PYTHON_MODULE(messaging)
{
class_<Message, boost::noncopyable>("Message", no_init);
class_<TextMessage, bases<Message>, boost::noncopyable>("TextMessage", no_init)
.add_property("text", &TextMessage::getText);
class_<MessageConsumer, boost::noncopyable>("MessageConsumer")
.def("receive", &MessageConsumer::receive,
return_value_policy<manage_new_object>());
}
And the test:
#!/usr/bin/env python
import os.path
import sys
from distutils.util import get_platform
plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3])
build_platlib = os.path.join('build', 'lib' + plat_specifier)
sys.path.insert(0, build_platlib)
from messaging import *
consumer = MessageConsumer()
msg = consumer.receive()
print msg
Run it like this:
rm -rf build ; python setup.py build ; ./test.py
With TEXTMESSAGE_IS_INTERFACE set to 0, I get:
<messaging.TextMessage object at 0xb7f04a74>
but with TEXTMESSAGE_IS_INTERFACE set to 1, I get:
<messaging.Message object at 0xb7ee1a74>
So the question is: is there a way to convince Boost to convert my
Message* to a TextMessage* (which in turn points to a TextMessageImpl)
if I can't wrap TextMessageImpl?
Thanks!
Regards,
Albert
More information about the Cplusplus-sig
mailing list