MatthieuW
MatthieuW

Reputation: 2372

How to wrap with boost-python a virtual class with a method returning a reference

I have two virtual classes I would like to wrap in boost python, I want to be able to write Python class that extends them. The thing is, one of the classes has a method that return a reference of the other class, and I can't figure how to do.

Here is a simplified version of code of class to be wrapped.

class Foo
{
    public:
    virtual ~Foo() {}
    virtual int a() = 0;
};

class Bar
{
    public:
    virtual ~Bar() {}
    virtual Foo const& b() = 0;
};

So I started wrapping about this way.

class FooWrap : public Foo, public wrapper<Foo>
{
    public:
    int a()
    {
        return this->get_override("a")();
    }
};

class BarWrap : public Bar, public wrapper<Bar>
{
    public:
    Foo const& b()
    {
        return this->get_override("b")();
    }
};

BOOST_PYTHON_MODULE(foobar)
{
    class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", pure_virtual(&Foo::a))
        ;
    class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", pure_virtual(&Bar::b))
        ;
}

And I get a compile error about "cannot instantiate abstract class [...] pure virtual function was not defined" "see declaration of 'foo::a'"

Upvotes: 3

Views: 3045

Answers (2)

babak
babak

Reputation: 774

The following code compiles for me. Inside your python Bar subclass you should be able to return a Foo instance from the b method.

#include <boost/python.hpp>

class Foo
{
public:
    virtual ~Foo() {}
    virtual int a() = 0;
};

class Bar
{
public:
    virtual ~Bar() {}
    virtual Foo const& b() = 0;
};


class FooWrap : public Foo, public boost::python::wrapper<Foo>
{
    public:
    int a()
    {
        return this->get_override("a")();
    }
};

class BarWrap : public Bar, public boost::python::wrapper<Bar>
{
    public:
    Foo const& b()
    {
        return this->get_override("b")();
    }
};

BOOST_PYTHON_MODULE(foobar)
{
    boost::python::class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", boost::python::pure_virtual(&Foo::a)) ;

    boost::python::class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", boost::python::pure_virtual(&Bar::b), boost::python::return_internal_reference<>());
}

Upvotes: 3

alex vasi
alex vasi

Reputation: 5344

I've been able to compile and run your code after I added call policy for Bar::b function:

BOOST_PYTHON_MODULE(foobar)
{
    class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", pure_virtual(&Foo::a));

    class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", pure_virtual(&Bar::b),
             return_internal_reference<>());
}

Basically, it's just means that lifetime of returned reference from Bar::b should be dependent on lifetime of Bar instance. You can read about call policies in boost docs.

What compiler and boost version are you using? I've got the following descriptive error with boost 1.46.0 and gcc 4.6.1:

error: no match for call to ‘(const boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<const Foo&>) (const Foo&)’

Upvotes: 4

Related Questions