[C++-sig] Doubts with wrapping/using abstract bases.

Prabhu Ramachandran prabhu at aero.iitm.ernet.in
Sun Aug 10 20:57:02 CEST 2003


Hi,

I think I have a fairly serious misunderstanding of how Boost.Python
wraps abstract virtual classes.  I'd appreciate any clarifications.

Here is a simple example:

// ---------------- holder.hpp ----------------------
#include <vector>
#include <iostream>

struct A {
    virtual ~A() {}
    virtual void f()=0;
};

struct B: A {
    void f() {std::cout << "B::f\n";}
};

struct Holder {
    Holder() {}
    void add(A* a) {arr.push_back(a);}
    A* get(const std::size_t n) {return arr[n];}    
private:
    std::vector<A*> arr;
};

void func(A* a) {a->f();}
// --------------------------------------------------

I wrap this with Pyste (CVS) and get wrapper code that looks like so
(edited for brevity):

// --------------------------------------------------
#include <boost/python.hpp>
#include <holder.hpp>

using namespace boost::python;

struct A_Wrapper: A
{
    A_Wrapper(PyObject* self_, const A& p0):  A(p0), self(self_) {}
    A_Wrapper(PyObject* self_): A(), self(self_) {}
    void f() {call_method< void >(self, "f");}
    PyObject* self;
};

struct B_Wrapper: B
{
    B_Wrapper(PyObject* self_, const B& p0): B(p0), self(self_) {}
    B_Wrapper(PyObject* self_): B(), self(self_) {}
    void f() {call_method< void >(self, "f");}
    void default_f() {B::f();}
    PyObject* self;
};

void add_wrapper(Holder* c, std::auto_ptr< B_Wrapper > o)
{c->add(o.get()); o.release();}

BOOST_PYTHON_MODULE(holder)
{
    class_< A, boost::noncopyable, std::auto_ptr< A_Wrapper > >
    ("A", init<  >());

    class_< B, bases< A > , std::auto_ptr< B_Wrapper > >("B", init<  >())
        .def(init< const B& >())
        .def("f", &B::f, (void (B_Wrapper::*)())&B_Wrapper::default_f);

    class_< Holder >("Holder", init<  >())
        .def(init< const Holder& >())
        .def("add", &add_wrapper)
        .def("get", &Holder::get, return_internal_reference< 1 >());

    def("func", &func);
}
// --------------------------------------------------

This looks good to me.  Now I try the following from Python:

>>> import holder
>>> b = holder.B()
>>> b.f()
B::f
>>> holder.func(b) 
B::f
>>> # Everything is OK.
>>> h = holder.Holder ()
>>> h.add(b)
>>> b1 = h.get(0)
>>> b1.f()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'A' object has no attribute 'f'

I did not expect this since this is perfectly legal in C++,
i.e. b1->f() in C++ is legal and used commonly.  So what am I doing
wrong?


Thanks!

cheers,
prabhu







More information about the Cplusplus-sig mailing list