diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b5ccf3c8..2996e537b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ set(PYBIND11_EXAMPLES example/example13.cpp example/example14.cpp example/example15.cpp + example/example16.cpp example/issues.cpp ) diff --git a/docs/changelog.rst b/docs/changelog.rst index f8f717bfd..00c9bb55c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,7 +5,8 @@ Changelog 1.5 (not yet released) ---------------------- -* Pickling support +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11. +* Pickling support for serializing and unserializing C++ instances to a byte stream in Python * Added a variadic ``make_tuple()`` function * Address a rare issue that could confuse the current virtual function dispatcher * Documentation improvements: import issues, symbol visibility, pickling, limitations diff --git a/example/example.cpp b/example/example.cpp index bc0ee417f..ba0ff2812 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -24,6 +24,7 @@ void init_ex12(py::module &); void init_ex13(py::module &); void init_ex14(py::module &); void init_ex15(py::module &); +void init_ex16(py::module &); void init_issues(py::module &); PYBIND11_PLUGIN(example) { @@ -44,6 +45,7 @@ PYBIND11_PLUGIN(example) { init_ex13(m); init_ex14(m); init_ex15(m); + init_ex16(m); init_issues(m); return m.ptr(); diff --git a/example/example16.cpp b/example/example16.cpp new file mode 100644 index 000000000..350435f57 --- /dev/null +++ b/example/example16.cpp @@ -0,0 +1,24 @@ +/* + example/example16.cpp -- automatic upcasting for polymorphic types + + Copyright (c) 2015 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "example.h" + +struct BaseClass { virtual ~BaseClass() {} }; +struct DerivedClass1 : BaseClass { }; +struct DerivedClass2 : BaseClass { }; + +void init_ex16(py::module &m) { + py::class_(m, "BaseClass").def(py::init<>()); + py::class_(m, "DerivedClass1").def(py::init<>()); + py::class_(m, "DerivedClass2").def(py::init<>()); + + m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); + m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); + m.def("return_none", []() -> BaseClass* { return nullptr; }); +} diff --git a/example/example16.py b/example/example16.py new file mode 100644 index 000000000..82102ea56 --- /dev/null +++ b/example/example16.py @@ -0,0 +1,12 @@ +from __future__ import print_function +import sys + +sys.path.append('.') + +from example import return_class_1 +from example import return_class_2 +from example import return_none + +print(type(return_class_1())) +print(type(return_class_2())) +print(type(return_none())) diff --git a/example/example16.ref b/example/example16.ref new file mode 100644 index 000000000..67fa6077d --- /dev/null +++ b/example/example16.ref @@ -0,0 +1,3 @@ + + + diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3fd9ab348..670c3afa0 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -137,6 +137,7 @@ public: PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, const std::type_info *type_info, + const std::type_info *type_info_backup, void *(*copy_constructor)(const void *), const void *existing_holder = nullptr) { void *src = const_cast(_src); @@ -153,6 +154,11 @@ public: return handle((PyObject *) it_instance->second).inc_ref(); auto it = internals.registered_types_cpp.find(std::type_index(*type_info)); + if (it == internals.registered_types_cpp.end()) { + type_info = type_info_backup; + it = internals.registered_types_cpp.find(std::type_index(*type_info)); + } + if (it == internals.registered_types_cpp.end()) { std::string tname = type_info->name(); detail::clean_type_id(tname); @@ -213,11 +219,11 @@ public: static handle cast(const type &src, return_value_policy policy, handle parent) { if (policy == return_value_policy::automatic) policy = return_value_policy::copy; - return type_caster_generic::cast(&src, policy, parent, &typeid(type), ©_constructor); + return cast(&src, policy, parent); } static handle cast(const type *src, return_value_policy policy, handle parent) { - return type_caster_generic::cast(src, policy, parent, &typeid(type), ©_constructor); + return type_caster_generic::cast(src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type), ©_constructor); } template using cast_op_type = pybind11::detail::cast_op_type; @@ -664,7 +670,9 @@ public: static handle cast(const holder_type &src, return_value_policy policy, handle parent) { return type_caster_generic::cast( - src.get(), policy, parent, &typeid(type), ©_constructor, &src); + src.get(), policy, parent, + src.get() ? &typeid(*src.get()) : nullptr, &typeid(type), + ©_constructor, &src); } protected: