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