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