Inheritance problem

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Inheritance problem

Erik Tuerke
Hi all,

currently i am facing a problem regarding inheritance with boost::python

Here is a simple code snippet:


class Base
{
public:
     virtual void print() { std::cout << "hello" << std::endl; }

};


class BaseWrapper : public Base, public wrapper<Base>
{
public:
BaseWrapper( PyObject *p ) : self(p) {}
BaseWrapper( PyObject *p, const Base &base) : Base(base), wrapper< Base
 >(), self(p) {}

     virtual void _print() { print(); }

private:
     PyObject const *self;
};

class Derived : public Base
{
public:
     Derived() {}
     Derived( PyObject *p ) : self(p){}
private:
     PyObject const *self;
};

BOOST_PYTHON_MODULE( my_module )
{

     class_<Base, BaseWrapper>( "Base", init<>() )
     .def("printIt", &BaseWrapper::_print)
     ;
     class_<Derived, bases<Base> >( "Derived", init<>() );
}

And in python i want to have the following reslut:

 >>import my_module
 >> derived = my_module.Derived()
 >> derived.printIt()

Actually this should print "hello" but instead throws an error saying:

derived.printIt()
Boost.Python.ArgumentError: Python argument types in
Base.printIt(Derived)
did not match C++ signature:
     printIt(_Base {lvalue})

I tried a lot of modification but always getting this message.
Does somebody of you know what i am missing?

Thanks a lot in advance!

Best regards!

--
Erik Türke
Department of Neurophysics
Max-Planck-Institute for Human Cognitive and Brain Sciences
Stephanstrasse 1A
04103 Leipzig
Germany
Tel: +49 341 99 40-2440
Email: [hidden email]
www.cbs.mpg.de

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Inheritance problem

Holger Joukl
Hi,

> currently i am facing a problem regarding inheritance with boost::python
>
> Here is a simple code snippet:
>
>
> class Base
> {
> public:
>      virtual void print() { std::cout << "hello" << std::endl; }
>
> };
>
> [...]
>
> And in python i want to have the following reslut:
>
>  >>import my_module
>  >> derived = my_module.Derived()
>  >> derived.printIt()
>
> Actually this should print "hello" but instead throws an error saying:
>
> derived.printIt()
> Boost.Python.ArgumentError: Python argument types in
> Base.printIt(Derived)
> did not match C++ signature:
>      printIt(_Base {lvalue})

Maybe I'm oversimplifying but if all you need is exposing some derived
class then
I don't see why you'd need all the BaseWrapper, self-pointer etc. stuff.

S.th. as simple as that should work:

// file cppcode.hpp

#include <iostream>

class Base
{
public:
     virtual void print() { std::cout << "hello Base" << std::endl; }

};


class Derived : public Base
{
public:
     virtual void print() { std::cout << "hello Derived" << std::endl; }


};

// only to show callback-into-python-overrides necessities
void callback(Base& base) {
    base.print();
}

// file wrap.cpp

#include <boost/python.hpp>
#include "cppcode.hpp"

namespace bp = boost::python;



BOOST_PYTHON_MODULE(cppcode)
{
    bp::class_<Base>("Base")
        .def("printIt", &Base::print)
     ;
    bp::class_<Derived, bp::bases<Base> >("Derived");
    bp::def("callback", &callback);
};



When run:

# file test.py
import cppcode

derived = cppcode.Derived()
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
    def printIt(self):
        print "hello PythonDerived"

pyderived = PythonDerived()
pyderived.printIt()
cppcode.callback(pyderived)

$ python2.7 -i ./test.py
hello Derived
hello Derived
hello PythonDerived
hello Base
>>>

Note that you'd need a Base wrapper class to actually make callbacks to
Python method-overrides work,
just as documented in
http://www.boost.org/doc/libs/1_47_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions

Holger


Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Inheritance problem

Erik Tuerke
On 10/14/11 10:29, Holger Joukl wrote:

> Hi,
>
>> currently i am facing a problem regarding inheritance with boost::python
>>
>> Here is a simple code snippet:
>>
>>
>> class Base
>> {
>> public:
>>       virtual void print() { std::cout<<  "hello"<<  std::endl; }
>>
>> };
>>
>> [...]
>>
>> And in python i want to have the following reslut:
>>
>>   >>import my_module
>>   >>  derived = my_module.Derived()
>>   >>  derived.printIt()
>>
>> Actually this should print "hello" but instead throws an error saying:
>>
>> derived.printIt()
>> Boost.Python.ArgumentError: Python argument types in
>> Base.printIt(Derived)
>> did not match C++ signature:
>>       printIt(_Base {lvalue})
> Maybe I'm oversimplifying but if all you need is exposing some derived
> class then
> I don't see why you'd need all the BaseWrapper, self-pointer etc. stuff.
>
> S.th. as simple as that should work:
>
> // file cppcode.hpp
>
> #include<iostream>
>
> class Base
> {
> public:
>       virtual void print() { std::cout<<  "hello Base"<<  std::endl; }
>
> };
>
>
> class Derived : public Base
> {
> public:
>       virtual void print() { std::cout<<  "hello Derived"<<  std::endl; }
>
>
> };
>
> // only to show callback-into-python-overrides necessities
> void callback(Base&  base) {
>      base.print();
> }
>
> // file wrap.cpp
>
> #include<boost/python.hpp>
> #include "cppcode.hpp"
>
> namespace bp = boost::python;
>
>
>
> BOOST_PYTHON_MODULE(cppcode)
> {
>      bp::class_<Base>("Base")
>          .def("printIt",&Base::print)
>       ;
>      bp::class_<Derived, bp::bases<Base>  >("Derived");
>      bp::def("callback",&callback);
> };
>
>
>
> When run:
>
> # file test.py
> import cppcode
>
> derived = cppcode.Derived()
> derived.printIt()
> cppcode.callback(derived)
>
> class PythonDerived(cppcode.Base):
>      def printIt(self):
>          print "hello PythonDerived"
>
> pyderived = PythonDerived()
> pyderived.printIt()
> cppcode.callback(pyderived)
>
> $ python2.7 -i ./test.py
> hello Derived
> hello Derived
> hello PythonDerived
> hello Base
> Note that you'd need a Base wrapper class to actually make callbacks to
> Python method-overrides work,
> just as documented in
> http://www.boost.org/doc/libs/1_47_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
>
> Holger
>
>
> Landesbank Baden-Wuerttemberg
> Anstalt des oeffentlichen Rechts
> Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
> HRA 12704
> Amtsgericht Stuttgart
>
> _______________________________________________
> Cplusplus-sig mailing list
> [hidden email]
> http://mail.python.org/mailman/listinfo/cplusplus-sig
Hi Holger,

thanks for your response.

Ok lets say my BaseClass has a member function called init( vector4 ):

class Base
{
public:
     void init( vector4 &vec ) { //doWhatEver }
     //a lot of other functions
};

Unfortunetaly i can not expose this init function directly to python so
i am writing a BaseWrapper

class BaseWrapper : public Base, public bp::wrapper<Base>
{
public:
     void _init( int first, int second, int third, int fourth) { init(
makeVec(first, second, third, fourth) ); }
     // a lot of other wrapper functions
};


And i have a derived class:

class Derived : Base
{
public:
     //some more functions
};

So when i am exposing Base and Derived like:


BOOST_PYTHON_MODULE( my_module )
{

     class_<Base, BaseWrapper>( "Base", init<>() )
     .def("init", &BaseWrapper::_init)
     ;
     class_<Derived, bases<Base> >( "Derived", init<>() );
}

I want to have all functions for objects of Derived that are available
in Base.
The thing is, that e.g. ipython recognizes the functions.
So in ipython, when i have an object of type Derived with tab completion
i see the functions from Base.
But when i try to call them i always get this "signature" error.

So i do not know how to use those callback approach you suggested.
Especially if you are using function overloading. And additionally, this
would mean, that i have to write such a callback function for each
function in my base class as a global function.

I think there is a much simpler way.

One thing i have to mention is, that it is perfectly working if i omit
the BaseWrapper class. So if the functions of Base can be exposed
without using a wrapper class:

class Base
{
public:
     void init( int first, int second, int third, int fourth ) {
//doWhatEver }
     //a lot of other functions
};

class Derived : public Base
{
};

BOOST_PYTHON_MODULE( my_module )
{

     class_<Base>( "Base", init<>() )
     .def("init", &Base::init)
     ;
     class_<Derived, bases<Base> >( "Derived", init<>() );
}

In python:

 >>derived = my_module.Derived()
 >>derived.init(3,1,2,2)

...works. But unfortunately not with the BaseWrapper Class :-(

Sorry for the long post...

Best regards!

--
Erik Türke
Department of Neurophysics
Max-Planck-Institute for Human Cognitive and Brain Sciences
Stephanstrasse 1A
04103 Leipzig
Germany
Tel: +49 341 99 40-2440
Email: [hidden email]
www.cbs.mpg.de

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Inheritance problem

Holger Joukl
Hi,

 > Ok lets say my BaseClass has a member function called init( vector4 ):

>
> class Base
> {
> public:
>      void init( vector4 &vec ) { //doWhatEver }
>      //a lot of other functions
> };
>
> Unfortunetaly i can not expose this init function directly to python so
> i am writing a BaseWrapper

Why's that? Can't you expose vector4 to Python?


> So when i am exposing Base and Derived like:
>
>
> BOOST_PYTHON_MODULE( my_module )
> {
>
>      class_<Base, BaseWrapper>( "Base", init<>() )
>      .def("init", &BaseWrapper::_init)
>      ;
>      class_<Derived, bases<Base> >( "Derived", init<>() );
> }
>
> I want to have all functions for objects of Derived that are available
> in Base.
> The thing is, that e.g. ipython recognizes the functions.
> So in ipython, when i have an object of type Derived with tab completion
> i see the functions from Base.
> But when i try to call them i always get this "signature" error.

I think the problem is that the Derived class doesn't actually have any
inheritance
relationship with BaseWrapper, i.e.
        Base
        /   \
       /     \
      /       \
BaseWrapper  Derived

So in an example like this

// file cppcode.hpp

#include <iostream>

class Base
{
protected:
    int m_area;
public:
    Base() : m_area(0) {}
    void init(int area) {
        m_area = area;
    }
    virtual void print() { std::cout << "hello Base " << m_area <<
std::endl; }

};


class Derived : public Base
{
public:
     virtual void print() { std::cout << "hello Derived "  << m_area <<
std::endl; }


};

// only to show callback-into-python-overrides necessities
void callback(Base& base) {
    base.print();
}


// file wrap.cpp

#include <boost/python.hpp>
#include "cppcode.hpp"

namespace bp = boost::python;


class BaseWrapper : public Base, public bp::wrapper<Base>
{
 public:
    void _init(int x, int y) {
        init(x * y);
    }
};


BOOST_PYTHON_MODULE(cppcode)
{
    bp::class_<BaseWrapper, boost::noncopyable>("Base")
        .def("init", &BaseWrapper::_init)
        .def("printIt", &Base::print)
     ;
    bp::class_<Derived, bp::bases<Base> >("Derived");
    bp::def("callback", &callback);
};


#!/apps/local/gcc/4.5.1/bin/python2.7

# file test.py

import cppcode

print "---> base"
base = cppcode.Base()
base.printIt()
base.init(3, 4)
base.printIt()


print "---> derived"
derived = cppcode.Derived()
derived.printIt()
derived.init(3, 4)
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
    def printIt(self):
        print "hello PythonDerived"

print "---> python derived"
pyderived = PythonDerived()
pyderived.printIt()
cppcode.callback(pyderived)

I run into this error when trying to call .init() on the Derived object:

$ python2.7 ./test.py
---> base
hello Base 0
hello Base 12
---> derived
hello Derived 0
Traceback (most recent call last):
  File "./test.py", line 23, in <module>
    derived.init(3, 4)
Boost.Python.ArgumentError: Python argument types in
    Base.init(Derived, int, int)
did not match C++ signature:
    init(BaseWrapper {lvalue}, int, int)


Which makes sense since Derived does not inherit from BaseWrapper.

> So i do not know how to use those callback approach you suggested.
> Especially if you are using function overloading. And additionally, this
> would mean, that i have to write such a callback function for each
> function in my base class as a global function.

Never mind the callback, I might have just confused you. The callback is
only for showing
that you'd need a Wrapper class if you want to inherit in Python and be
able to call back
from C++ into Python and actually call methods overridden in Python.

> One thing i have to mention is, that it is perfectly working if i omit
> the BaseWrapper class. So if the functions of Base can be exposed
> without using a wrapper class:
> [...]
> ...works. But unfortunately not with the BaseWrapper Class :-(

Because now you don't have the problem that Derived has no inheritance
relationship with BaseWrapper.

Maybe you can just use a free function:

// file wrap.cpp

#include <boost/python.hpp>
#include "cppcode.hpp"

namespace bp = boost::python;


void _init(Base& base, int x, int y) {
        base.init(x * y);
}


BOOST_PYTHON_MODULE(cppcode)
{
    bp::class_<Base>("Base")
        .def("init", &_init)
        .def("printIt", &Base::print)
     ;
    bp::class_<Derived, bp::bases<Base> >("Derived");
    bp::def("callback", &callback);
};



# file test.py


import os
import sys


import cppcode

print "---> base"
base = cppcode.Base()
base.printIt()
base.init(3, 4)
base.printIt()


print "---> derived"
derived = cppcode.Derived()
derived.printIt()
derived.init(3, 4)
derived.printIt()
cppcode.callback(derived)

class PythonDerived(cppcode.Base):
    def printIt(self):
        print "hello PythonDerived"

print "---> python derived"
pyderived = PythonDerived()
pyderived.printIt()
# to make this invoke PythonDerived.printIt() you need a wrapper class
cppcode.callback(pyderived)

===>

$ python2.7 ./test.py
---> base
hello Base 0
hello Base 12
---> derived
hello Derived 0
hello Derived 12
hello Derived 12
---> python derived
hello PythonDerived
hello Base 0
>>>

Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Inheritance problem

Erik Tuerke
On 10/14/11 16:48, Holger Joukl wrote:

> Hi,
>
>   >  Ok lets say my BaseClass has a member function called init( vector4 ):
>> class Base
>> {
>> public:
>>       void init( vector4&vec ) { //doWhatEver }
>>       //a lot of other functions
>> };
>>
>> Unfortunetaly i can not expose this init function directly to python so
>> i am writing a BaseWrapper
> Why's that? Can't you expose vector4 to Python?
>
>
>> So when i am exposing Base and Derived like:
>>
>>
>> BOOST_PYTHON_MODULE( my_module )
>> {
>>
>>       class_<Base, BaseWrapper>( "Base", init<>() )
>>       .def("init",&BaseWrapper::_init)
>>       ;
>>       class_<Derived, bases<Base>  >( "Derived", init<>() );
>> }
>>
>> I want to have all functions for objects of Derived that are available
>> in Base.
>> The thing is, that e.g. ipython recognizes the functions.
>> So in ipython, when i have an object of type Derived with tab completion
>> i see the functions from Base.
>> But when i try to call them i always get this "signature" error.
> I think the problem is that the Derived class doesn't actually have any
> inheritance
> relationship with BaseWrapper, i.e.
>          Base
>          /   \
>         /     \
>        /       \
> BaseWrapper  Derived
>
> So in an example like this
>
> // file cppcode.hpp
>
> #include<iostream>
>
> class Base
> {
> protected:
>      int m_area;
> public:
>      Base() : m_area(0) {}
>      void init(int area) {
>          m_area = area;
>      }
>      virtual void print() { std::cout<<  "hello Base "<<  m_area<<
> std::endl; }
>
> };
>
>
> class Derived : public Base
> {
> public:
>       virtual void print() { std::cout<<  "hello Derived "<<  m_area<<
> std::endl; }
>
>
> };
>
> // only to show callback-into-python-overrides necessities
> void callback(Base&  base) {
>      base.print();
> }
>
>
> // file wrap.cpp
>
> #include<boost/python.hpp>
> #include "cppcode.hpp"
>
> namespace bp = boost::python;
>
>
> class BaseWrapper : public Base, public bp::wrapper<Base>
> {
>   public:
>      void _init(int x, int y) {
>          init(x * y);
>      }
> };
>
>
> BOOST_PYTHON_MODULE(cppcode)
> {
>      bp::class_<BaseWrapper, boost::noncopyable>("Base")
>          .def("init",&BaseWrapper::_init)
>          .def("printIt",&Base::print)
>       ;
>      bp::class_<Derived, bp::bases<Base>  >("Derived");
>      bp::def("callback",&callback);
> };
>
>
> #!/apps/local/gcc/4.5.1/bin/python2.7
>
> # file test.py
>
> import cppcode
>
> print "--->  base"
> base = cppcode.Base()
> base.printIt()
> base.init(3, 4)
> base.printIt()
>
>
> print "--->  derived"
> derived = cppcode.Derived()
> derived.printIt()
> derived.init(3, 4)
> derived.printIt()
> cppcode.callback(derived)
>
> class PythonDerived(cppcode.Base):
>      def printIt(self):
>          print "hello PythonDerived"
>
> print "--->  python derived"
> pyderived = PythonDerived()
> pyderived.printIt()
> cppcode.callback(pyderived)
>
> I run into this error when trying to call .init() on the Derived object:
>
> $ python2.7 ./test.py
> --->  base
> hello Base 0
> hello Base 12
> --->  derived
> hello Derived 0
> Traceback (most recent call last):
>    File "./test.py", line 23, in<module>
>      derived.init(3, 4)
> Boost.Python.ArgumentError: Python argument types in
>      Base.init(Derived, int, int)
> did not match C++ signature:
>      init(BaseWrapper {lvalue}, int, int)
>
>
> Which makes sense since Derived does not inherit from BaseWrapper.
>
>> So i do not know how to use those callback approach you suggested.
>> Especially if you are using function overloading. And additionally, this
>> would mean, that i have to write such a callback function for each
>> function in my base class as a global function.
> Never mind the callback, I might have just confused you. The callback is
> only for showing
> that you'd need a Wrapper class if you want to inherit in Python and be
> able to call back
> from C++ into Python and actually call methods overridden in Python.
>
>> One thing i have to mention is, that it is perfectly working if i omit
>> the BaseWrapper class. So if the functions of Base can be exposed
>> without using a wrapper class:
>> [...]
>> ...works. But unfortunately not with the BaseWrapper Class :-(
> Because now you don't have the problem that Derived has no inheritance
> relationship with BaseWrapper.
>
> Maybe you can just use a free function:
>
> // file wrap.cpp
>
> #include<boost/python.hpp>
> #include "cppcode.hpp"
>
> namespace bp = boost::python;
>
>
> void _init(Base&  base, int x, int y) {
>          base.init(x * y);
> }
>
>
> BOOST_PYTHON_MODULE(cppcode)
> {
>      bp::class_<Base>("Base")
>          .def("init",&_init)
>          .def("printIt",&Base::print)
>       ;
>      bp::class_<Derived, bp::bases<Base>  >("Derived");
>      bp::def("callback",&callback);
> };
>
>
>
> # file test.py
>
>
> import os
> import sys
>
>
> import cppcode
>
> print "--->  base"
> base = cppcode.Base()
> base.printIt()
> base.init(3, 4)
> base.printIt()
>
>
> print "--->  derived"
> derived = cppcode.Derived()
> derived.printIt()
> derived.init(3, 4)
> derived.printIt()
> cppcode.callback(derived)
>
> class PythonDerived(cppcode.Base):
>      def printIt(self):
>          print "hello PythonDerived"
>
> print "--->  python derived"
> pyderived = PythonDerived()
> pyderived.printIt()
> # to make this invoke PythonDerived.printIt() you need a wrapper class
> cppcode.callback(pyderived)
>
> ===>
>
> $ python2.7 ./test.py
> --->  base
> hello Base 0
> hello Base 12
> --->  derived
> hello Derived 0
> hello Derived 12
> hello Derived 12
> --->  python derived
> hello PythonDerived
> hello Base 0
> Holger
>
> Landesbank Baden-Wuerttemberg
> Anstalt des oeffentlichen Rechts
> Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
> HRA 12704
> Amtsgericht Stuttgart
>
> _______________________________________________
> Cplusplus-sig mailing list
> [hidden email]
> http://mail.python.org/mailman/listinfo/cplusplus-sig
Hi Holger,

well, ok, i understand now what the problem is. Many thanks for your help!

Best Regards!

--
Erik Türke
Department of Neurophysics
Max-Planck-Institute for Human Cognitive and Brain Sciences
Stephanstrasse 1A
04103 Leipzig
Germany
Tel: +49 341 99 40-2440
Email: [hidden email]
www.cbs.mpg.de

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig