[C++-sig] Missing definitions for virtual methods in Pyste-generated code

David Abrahams dave at boost-consulting.com
Fri Mar 21 21:18:30 CET 2003


Patrick Hartling <patrick at vrac.iastate.edu> writes:

> In my continued experimentation with Pyste, I have run into a problem
> relating to virtual methods.  I have attached example code that
> demonstrates the problem specifically, but I will try to explain it in
> general terms here.
>
> First, the class structure is similar to this:
>
> class A
> {
> public:
>     virtual void f1();
> };
>
> class B : public A
> {
> public:
>     virtual void f2();
> };
>
> My goal, then, is to derive from B a class C written in Python:
>
> class C(MyModule.B):
>     def __init__(self):
>        MyModule.B.__init__(self)
>
>     def f1(self):
>        # Do something ...
>
>     def f2(self):
>        # Do something else ...
>
> Ultimately, an instance of C will be handed off to some C++ code where
> it needs to be treated polymorphically as an instance of either A or
> B, depending on the context.
>
> In Pyste, I declare that I want to expose both A and B to
> Python. However, the Boost.Python code that gets generated for class B
> is missing the definition for the f1() method that is inherited from
> class A:
>
> class_< B, bases< A > , boost::noncopyable, B_Wrapper >("B", init<  >())
>      .def("f2", &B::f2, &B_Wrapper::default_f2)
> ;
>
> Without the definition for the f1() member function, C.f1() is never
> invoked by the C++ code.  C.f2() works fine, however.  I can easily
> modify the generated Boost.Python code to add the definition of f1(),
> but this seems like a bug in how Pyste deals with inherited member
> functions.

Something is slightly wrong with your analysis:

1. The generated code for wrapping A should contain a definition of f1

2. That's not what causes C.f1 to be called when invoked from C++
   anyway: it's the override in the wrapper class for A which I
   presume from reading the code above should be called A_Wrapper
   that makes sure C.f1 gets called.

...and now I see the problem.  For scenarios like this, the Wrapper
classes really need to use virtual inheritance.  It should look
something like this:

struct A_Wrapper : virtual A
{
    A_Wrapper(PyObject* self) : self(self) {}
    void f1() { call_method<void>(self, "f1"); }
    void A_f1() { this->A::f1(); }
};

// note inheritance from A_Wrapper
struct B_Wrapper : A_Wrapper, virtual B 
{
    B_Wrapper(PyObject* self) : self(self) {}
    void f2() { call_method<void>(self, "f2"); }
    void B_f2() { this->B::f2(); }
};

HTH,
-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com





More information about the Cplusplus-sig mailing list