diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 53c5d2f3..67861b49 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -20,17 +20,6 @@ # include # include -# include -# include -# include -# include - -# include -# include -# include -# include -# include - # include # include # include @@ -44,6 +33,18 @@ # include # include +# include +# include +# include +# include + +# include +# include +# include +# include +# include +# include + # include # include @@ -106,6 +107,27 @@ namespace detail SelectHolder::register_(); } + // + // register_wrapper_class -- register the relationship between a + // virtual function callback wrapper class and the class being + // wrapped. + // + template + inline void register_wrapper_class(T*, T*, int) {} + + template + inline void register_wrapper_class(Wrapper*, T*, ...) + { + objects::register_class_from_python >(); + objects::copy_class_object(type_id(), type_id()); + } + + template + inline void register_wrapper_class(Held* = 0, T* = 0) + { + register_wrapper_class((Held*)0, (T*)0, 0); + } + # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING template struct is_data_member_pointer @@ -562,6 +584,12 @@ inline void class_::register_() const { objects::register_class_from_python(); + typedef BOOST_DEDUCED_TYPENAME holder_selector::type select_holder; + typedef BOOST_DEDUCED_TYPENAME select_holder::type holder; + typedef BOOST_DEDUCED_TYPENAME holder::held_type held_t; + + detail::register_wrapper_class(); + detail::register_class_to_python( mpl::bool_() # if BOOST_WORKAROUND(__MWERKS__, <= 0x2407) diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp index 2417ed4a..45bffbf7 100644 --- a/include/boost/python/object/class.hpp +++ b/include/boost/python/object/class.hpp @@ -58,6 +58,8 @@ struct BOOST_PYTHON_DECL class_base : python::api::object void make_method_static(const char *method_name); }; +BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst); + }}} // namespace boost::python::objects #endif // CLASS_DWA20011214_HPP diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index cc114925..7b0796ad 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -52,6 +52,7 @@ bool is_null(T* p, int) template struct pointer_holder : instance_holder { + typedef Value held_type; typedef Value value_type; pointer_holder(Pointer); @@ -73,9 +74,7 @@ struct pointer_holder : instance_holder template struct pointer_holder_back_reference : instance_holder { - private: typedef typename python::pointee::type held_type; - public: typedef Value value_type; // Not sure about this one -- can it work? The source object diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index c83bb9c7..89e52352 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -37,10 +37,11 @@ namespace boost { namespace python { namespace objects { # define BOOST_PYTHON_UNFORWARD_LOCAL(z, n, _) BOOST_PP_COMMA_IF(n) objects::do_unforward(a##n,0) # endif -template +template struct value_holder : instance_holder { - typedef Held value_type; + typedef Value held_type; + typedef Value value_type; // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 1)) @@ -50,13 +51,14 @@ struct value_holder : instance_holder void* holds(type_info); private: // data members - Held m_held; + Value m_held; }; -template +template struct value_holder_back_reference : instance_holder { - typedef Held value_type; + typedef Held held_type; + typedef Value value_type; // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 2)) @@ -66,29 +68,29 @@ private: // required holder implementation void* holds(type_info); private: // data members - BackReferenceType m_held; + Held m_held; }; # undef BOOST_PYTHON_UNFORWARD_LOCAL -template -void* value_holder::holds(type_info dst_t) +template +void* value_holder::holds(type_info dst_t) { - type_info src_t = python::type_id(); + type_info src_t = python::type_id(); return src_t == dst_t ? &m_held : find_static_type(&m_held, src_t, dst_t); } -template -void* value_holder_back_reference::holds( +template +void* value_holder_back_reference::holds( type_info dst_t) { - type_info src_t = python::type_id(); - Held* x = &m_held; + type_info src_t = python::type_id(); + Value* x = &m_held; if (dst_t == src_t) return x; - else if (dst_t == python::type_id()) + else if (dst_t == python::type_id()) return &m_held; else return find_static_type(x, src_t, dst_t); diff --git a/src/object/class.cpp b/src/object/class.cpp index 2a95448a..9e11c534 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -521,6 +521,16 @@ namespace objects converters.m_class_object = (PyTypeObject*)incref(this->ptr()); } + BOOST_PYTHON_DECL void copy_class_object(type_info const& src, type_info const& dst) + { + converter::registration& dst_converters + = const_cast(converter::registry::lookup(dst)); + + converter::registration const& src_converters = converter::registry::lookup(src); + + dst_converters.m_class_object = src_converters.m_class_object; + } + void class_base::set_instance_size(std::size_t instance_size) { this->attr("__instance_size__") = instance_size; diff --git a/test/polymorphism.cpp b/test/polymorphism.cpp index 02ec7b57..551c9024 100644 --- a/test/polymorphism.cpp +++ b/test/polymorphism.cpp @@ -52,6 +52,28 @@ struct C : A virtual std::string f() { return "C::f()"; } }; +struct D : A +{ + virtual std::string f() { return "D::f()"; } + std::string g() { return "D::g()"; } +}; + +struct DCallback : D, Callback +{ + DCallback (PyObject* self) : Callback(self) {} + + std::string f() + { + return call_method(mSelf, "f"); + } + + std::string default_f() + { + return A::f(); + } +}; + + A& getBCppObj () { static B b; @@ -79,6 +101,8 @@ C& getCCppObj () return c; } +A* pass_a(A* x) { return x; } + BOOST_PYTHON_MODULE_INIT(polymorphism_ext) { class_("A") @@ -91,6 +115,13 @@ BOOST_PYTHON_MODULE_INIT(polymorphism_ext) .def("f", &C::f) ; + class_,DCallback,boost::noncopyable>("D") + .def("f", &D::f, &DCallback::default_f) + .def("g", &D::g) + ; + + def("pass_a", &pass_a, return_internal_reference<>()); + def("getCCppObj", getCCppObj, return_value_policy()); def("factory", factory, return_value_policy()); diff --git a/test/polymorphism.py b/test/polymorphism.py index a305bbea..d9bd763b 100644 --- a/test/polymorphism.py +++ b/test/polymorphism.py @@ -32,17 +32,21 @@ class PolymorphTest(unittest.TestCase): self.failUnlessEqual(type(factory(1)), A) self.failUnlessEqual(type(factory(2)), C) - def testReturnPy(self): + def test_return_py(self): - class D(A): + class X(A): def f(self): - return 'D.f' + return 'X.f' - d = D() + x = X() - self.failUnlessEqual ('D.f', d.f()) - self.failUnlessEqual ('D.f', call_f(d)) + self.failUnlessEqual ('X.f', x.f()) + self.failUnlessEqual ('X.f', call_f(x)) + def test_wrapper_downcast(self): + a = pass_a(D()) + self.failUnlessEqual('D::g()', a.g()) + if __name__ == "__main__": # remove the option which upsets unittest