Boost.Python: Polymorphism downcasting

Hi, I have a list of base classes in C++, I want to access them in Python as a list of their derived most classes. Is there a build in means to cater for this in Boost.Python? I've made an example the problem I ma facing: // ------------------------------- Code ----------------------------------// #include<memory> #include<iostream> #include<vector> namespace boost { template<class T> T* get_pointer(std::shared_ptr<T>& p){ return p.get(); }} struct Vehicle{ virtual ~Vehicle(){} friend bool operator==(const Vehicle& lhs, const Vehicle& rhs) { return true; }}; struct Boat: public Vehicle{ virtual ~Boat(){} friend bool operator==(const Boat& lhs, const Boat& rhs) { return true; } char const* testBoatSpecificMethod() { return "Floating."; } }; struct Truck: public Vehicle{ virtual ~Truck(){} friend bool operator==(const Truck& lhs, const Truck& rhs) { return true; } char const* testTruckSpecificMethod() { return "Trucking."; } }; class Garage { public: Garage() {}; ~Garage() {}; char const* test() { std::string temp = "Vehicle List Size: " + std::to_string(m_VehicleList.size()); return temp.c_str(); } friend bool operator==(const Garage& lhs, const Garage& rhs) { return true; } std::vector<Vehicle>& vehicleList() { return m_VehicleList; } private: std::vector<Vehicle> m_VehicleList; }; #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> BOOST_PYTHON_MODULE(garage_ext) { using namespace boost::python; class_<Garage>("Garage") .def("test", &Garage::test) .def("vehicleList", &Garage::vehicleList, return_internal_reference<1>()); class_<Vehicle,std::shared_ptr<Vehicle>>("Vehicle"); class_<Boat,std::shared_ptr<Boat>,bases<Vehicle>>("Boat") .def("testBoatSpecificMethod", &Boat::testBoatSpecificMethod); class_<Truck,std::shared_ptr<Truck>,bases<Vehicle>>("Truck") .def("testTruckSpecificMethod", &Truck::testTruckSpecificMethod); implicitly_convertible<std::shared_ptr<Boat>,std::shared_ptr<Vehicle>>(); implicitly_convertible<std::shared_ptr<Truck>,std::shared_ptr<Vehicle>>(); class_<std::vector<Vehicle> >("stl_vector_Vehicle") .def(vector_indexing_suite<std::vector<Vehicle> >()); } // --------------------------- Test Script -------------------------------// import garage_ext g = garage_ext.Garage() l = g.vehicleList() l.append(garage_ext.Boat()) print "Expecting a Boat object:" print str(l[0]) print g.vehicleList()[0].testBoatSpecificMethod() garage_ext.f2("Done.") // ------------------------------ Output ---------------------------------// Expecting a Boat object <garage_ext.Vehicle object at 0x7fb17a3bfb50> Traceback (most recent call last): File "test_garage.py", line 7, in <module> print g.vehicleList()[0].testBoatSpecificMethod() AttributeError: *'Vehicle' object has no attribute 'testBoatSpecificMethod'* *'Vehicle' object has no attribute 'testBoatSpecificMethod'* Here I want Vehicle to be a Boat object. If there is not a build in or recommended/known Boost.Python means to handle this problem, I'm thinking of wrapping the list (Lots of accessors to be wrapped in my library.) with a get accessor returning a boost::python::list, storing the derived most types. Getting the derived most type possibly by calling overriden 'getAsDerivedClass' method. I would like to avoid this. I dislike having to add python usage specific methods to the library, for our design and vision values / reasons. Kind Regards, Christoff

UPDATE: I erroneously created the example without the vehicle list being a list of smart pointer. I get the exact same output with the list being a list of smart pointers. When it is a list of raw pointers, it works as desired. What can I change to make the list of smart pointers behave like raw pointers? Making it boost::shared_ptrs instead of std::shared_ptrs makes no difference. Kind Regards, Christoff On 13 October 2014 16:30, Christoff Kok <christoff.kok@ex-mente.co.za> wrote:
Hi,
I have a list of base classes in C++, I want to access them in Python as a list of their derived most classes.
Is there a build in means to cater for this in Boost.Python?
I've made an example the problem I ma facing:
// ------------------------------- Code ----------------------------------// #include<memory> #include<iostream> #include<vector> namespace boost { template<class T> T* get_pointer(std::shared_ptr<T>& p){ return p.get(); }}
struct Vehicle{ virtual ~Vehicle(){} friend bool operator==(const Vehicle& lhs, const Vehicle& rhs) { return true; }}; struct Boat: public Vehicle{ virtual ~Boat(){} friend bool operator==(const Boat& lhs, const Boat& rhs) { return true; } char const* testBoatSpecificMethod() { return "Floating."; } }; struct Truck: public Vehicle{ virtual ~Truck(){} friend bool operator==(const Truck& lhs, const Truck& rhs) { return true; } char const* testTruckSpecificMethod() { return "Trucking."; } };
class Garage { public: Garage() {}; ~Garage() {}; char const* test() { std::string temp = "Vehicle List Size: " + std::to_string(m_VehicleList.size()); return temp.c_str(); } friend bool operator==(const Garage& lhs, const Garage& rhs) { return true; } std::vector<Vehicle>& vehicleList() { return m_VehicleList; } private: std::vector<Vehicle> m_VehicleList; };
#include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> BOOST_PYTHON_MODULE(garage_ext) { using namespace boost::python; class_<Garage>("Garage") .def("test", &Garage::test) .def("vehicleList", &Garage::vehicleList, return_internal_reference<1>()); class_<Vehicle,std::shared_ptr<Vehicle>>("Vehicle"); class_<Boat,std::shared_ptr<Boat>,bases<Vehicle>>("Boat") .def("testBoatSpecificMethod", &Boat::testBoatSpecificMethod); class_<Truck,std::shared_ptr<Truck>,bases<Vehicle>>("Truck") .def("testTruckSpecificMethod", &Truck::testTruckSpecificMethod);
implicitly_convertible<std::shared_ptr<Boat>,std::shared_ptr<Vehicle>>();
implicitly_convertible<std::shared_ptr<Truck>,std::shared_ptr<Vehicle>>(); class_<std::vector<Vehicle> >("stl_vector_Vehicle") .def(vector_indexing_suite<std::vector<Vehicle> >()); }
// --------------------------- Test Script -------------------------------// import garage_ext g = garage_ext.Garage() l = g.vehicleList() l.append(garage_ext.Boat()) print "Expecting a Boat object:" print str(l[0]) print g.vehicleList()[0].testBoatSpecificMethod() garage_ext.f2("Done.")
// ------------------------------ Output ---------------------------------// Expecting a Boat object <garage_ext.Vehicle object at 0x7fb17a3bfb50> Traceback (most recent call last): File "test_garage.py", line 7, in <module> print g.vehicleList()[0].testBoatSpecificMethod() AttributeError: *'Vehicle' object has no attribute 'testBoatSpecificMethod'*
*'Vehicle' object has no attribute 'testBoatSpecificMethod'* Here I want Vehicle to be a Boat object.
If there is not a build in or recommended/known Boost.Python means to handle this problem, I'm thinking of wrapping the list (Lots of accessors to be wrapped in my library.) with a get accessor returning a boost::python::list, storing the derived most types. Getting the derived most type possibly by calling overriden 'getAsDerivedClass' method. I would like to avoid this. I dislike having to add python usage specific methods to the library, for our design and vision values / reasons.
Kind Regards, Christoff
-- Christoff Kok Software Engineer Ex Mente http://www.ex-mente.co.za christoff.kok@ex-mente.co.za PO Box 10214 Centurion 0046 South Africa tel: +27 12 743 6993 tel: +27 12 654 8198 fax: +27 85 150 1341
participants (1)
-
Christoff Kok