#include #include #include "pybind11_tests.h" #include #include #include namespace test_class_sh_mi_thunks { // For general background: https://shaharmike.com/cpp/vtable-part2/ // C++ vtables - Part 2 - Multiple Inheritance // ... the compiler creates a 'thunk' method that corrects `this` ... struct Base0 { virtual ~Base0() = default; Base0() = default; Base0(const Base0 &) = delete; }; struct Base1 { virtual ~Base1() = default; // Using `vector` here because it is known to make this test very sensitive to bugs. std::vector vec = {1, 2, 3, 4, 5}; Base1() = default; Base1(const Base1 &) = delete; }; struct Derived : Base1, Base0 { ~Derived() override = default; Derived() = default; Derived(const Derived &) = delete; }; } // namespace test_class_sh_mi_thunks PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base0) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Derived) TEST_SUBMODULE(class_sh_mi_thunks, m) { using namespace test_class_sh_mi_thunks; m.def("ptrdiff_drvd_base0", []() { auto drvd = std::unique_ptr(new Derived); auto *base0 = dynamic_cast(drvd.get()); return std::ptrdiff_t(reinterpret_cast(drvd.get()) - reinterpret_cast(base0)); }); py::classh(m, "Base0"); py::classh(m, "Base1"); py::classh(m, "Derived"); m.def( "get_drvd_as_base0_raw_ptr", []() { auto *drvd = new Derived; auto *base0 = dynamic_cast(drvd); return base0; }, py::return_value_policy::take_ownership); m.def("get_drvd_as_base0_shared_ptr", []() { auto drvd = std::make_shared(); auto base0 = std::dynamic_pointer_cast(drvd); return base0; }); m.def("get_drvd_as_base0_unique_ptr", []() { auto drvd = std::unique_ptr(new Derived); auto base0 = std::unique_ptr(std::move(drvd)); return base0; }); m.def("vec_size_base0_raw_ptr", [](const Base0 *obj) { const auto *obj_der = dynamic_cast(obj); if (obj_der == nullptr) { return std::size_t(0); } return obj_der->vec.size(); }); m.def("vec_size_base0_shared_ptr", [](const std::shared_ptr &obj) -> std::size_t { const auto obj_der = std::dynamic_pointer_cast(obj); if (!obj_der) { return std::size_t(0); } return obj_der->vec.size(); }); m.def("vec_size_base0_unique_ptr", [](std::unique_ptr obj) -> std::size_t { const auto *obj_der = dynamic_cast(obj.get()); if (obj_der == nullptr) { return std::size_t(0); } return obj_der->vec.size(); }); }