On 10/11/2010 10:49 AM, Marek Denis wrote:
On 11.10.2010 00:42, Jim Bosch wrote:
Essentially, what you need to do is pass a Python object to call_method
(boost::python::object or PyObject *) that already contains your C++
object. In order to get one, you need need to tell Boost.Python to
construct A and B with what it calls a "back reference". Your C++
constructors will be given a PyObject* by boost.python, pointing to the
Python objects the C++ object will be wrapped in, and you can then store
those as data members and pass the PyObject * to call_method. You can
find more information in the Boost.Python reference docs on class_,
especially the "HeldType Semantics" section.
I did checked the docs, but I think I don't get how should it be done in
my case. What they talk about (as well as in the provided example)
They let the user to create Python classes derived from C++ classes and
launchind virtual Python function. Would ou mind providing a sample
piece of code how should it be done to wrap my C++ object into PyObject*
? Thanks in advance.
I think this is something like what you want to do:
-----------------------------------------
namespace bp = boost::python
class A {
public:
std::string getData() { return _data; }
void setCallback(bp::object const & callback) {
_callback = callback;
}
bp::object invokeCallback() {
return _callback(getSelf());
}
virtual PyObject * getSelf() const = 0;
virtual ~A() {}
explicit A(std::string const & data) : _data(data) {}
private:
std::string _data;
bp::object _callback;
};
class B : public A {
public:
explicit B(std::string const & data) : A(data) {}
};
class PyA : public A {
public:
PyA(PyObject * self, std::string const & data) :
A(data), _self(self) {}
virtual PyObject * getSelf() const { return _self; }
private:
PyObject * _self;
};
class PyB : public B {
public:
PyB(PyObject * self, std::string const & data) :
B(data), _self(self) {}
virtual PyObject * getSelf() const { return _self; }
private:
PyObject * _self;
};
BOOST_PYTHON_MODULE(example) {
bp::class_<A,PyA>("A", bp::init<std::string>(bp::arg("data")))
.add_property("data", &A::getData)
.def("setCallback", &A::setCallback)
.def("invokeCallback", &A::invokeCallback)
bp::class_<B,bp::bases<A>,PyB>(
"B",
bp::init<std::string>(bp::arg("data"))
);
}
-----------------------------------------
A couple of notes:
- I have not tested this. Likely there are some typos, and possibly
even a bit of forgotten syntax - hopefully it's easy to correct.
- Note that there's no need to re-wrap the methods that B inherits from
A, but you do have create both PyA and PyB if you want both A and B to
be instantiable from Python (after all, getSelf() is pure virtual).
- If you have a C++ function that returns an A or B instance by
reference or pointer, this code will still work. Of course, such an
object will have to find some other way to implement getSelf() - only
objects instantiated in Python will actually be PyA or PyB instances.
- I didn't actually use call_method anywhere, because bp::object has an
overloaded operator() that does what you need (and using object here is
better than PyObject because it handles the reference counting; you
don't use it for _self because we don't want reference counting there).
- This is a little non-standard because the base classes A and B are
Python-aware and are pure virtual - but that makes sense, because your
pattern requires that all C++ objects have a back-reference to their
Python selves.
- I think there's a way to do this that merges each class with it's
Python counterpart (i.e., it tells Boost.Python that A has a constructor
that takes the special "self" argument), and it has something to do with
specializing a template traits class. But I haven't ever done it, and I
don't want to lead you astray.
HTH!
Jim
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig