[C++-sig] Missing definitions for virtual methods in Pyste-generated code
Nicodemus
nicodemus at globalite.com.br
Fri Mar 21 21:54:28 CET 2003
David Abrahams wrote:
>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,
>
Unfortunetely I get the same output, even after this changes. From what
I understand, they should work too. Do you have any other idea Dave? I
cleaned the examples from Patrick a bit, and here are they for reference:
------------ test.h
#include <iostream>
using namespace std;
struct A
{
virtual void f1() { cout << "A::f1" << endl; }
};
struct B: public A
{
virtual void f2() { cout << "B::f2" << endl; }
};
void call(A* a)
{
a->f1();
B* b = dynamic_cast<B*>(a);
b->f2();
}
------------ test.cpp (generated, and then manual-changed)
#include <boost/python.hpp>
#include <test.h>
using namespace boost::python;
struct A_Wrapper: virtual A
{
A_Wrapper(PyObject* self_, const A & p0):
A(p0), self(self_) {}
A_Wrapper(PyObject* self_):
A(), self(self_) {}
void f1() {
call_method< void >(self, "f1");
}
void default_f1() {
A::f1();
}
PyObject* self;
};
struct B_Wrapper: virtual B, A_Wrapper
{
B_Wrapper(PyObject* self_, const B & p0):
B(p0), A_Wrapper(self_), self(self_) {}
B_Wrapper(PyObject* self_):
B(), A_Wrapper(self_), self(self_) {}
void f2() {
call_method< void >(self, "f2");
}
void default_f2() {
B::f2();
}
PyObject* self;
};
BOOST_PYTHON_MODULE(test)
{
def("call", &call);
class_< A, A_Wrapper >("A", init< >())
.def(init< const A & >())
.def("f1", &A::f1, &A_Wrapper::default_f1)
;
class_< B, bases< A > , B_Wrapper >("B", init< >())
.def(init< const B & >())
.def("f2", &B::f2, &B_Wrapper::default_f2)
;
}
----------------- test.py
from test import *
class C(B):
def __init__(self):
B.__init__(self)
def f1(self): print 'C.f1'
def f2(self): print 'C.f2'
call(C())
------------------- output
A::f1
C.f2
More information about the Cplusplus-sig
mailing list