Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

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

Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

Adam Preble
I am seeing this come up in many variations, with people doing slightly different things.  I haven't yet seen an example doing something in this exact progression.  I apologize here because I feel like I'm repeating a topic that has come up on the list before--even just a few weeks back.  Here's what I'm trying to do:

1. Expose a base class with a pure virtual method.
2. Expose an acceptor class that accepts that base class as an argument for a method.
3. Implement the base class in Python
4. Pass that implemented class to the acceptor

I am using Boost 1.42.

I have some source snippets.  I am using the wrapper method, though without it I had the same result:

    class BaseTest
    {
    public:
        virtual int GimmeNumber() = 0;
        virtual ~BaseTest() {}
    };

    class BaseTestWrap : public BaseTest, public wrapper<BaseTest>
    {
        int GimmeNumber()
        {
            return this->get_override("GimmeNumber")();
        }
    };

    class ITakeFoo
    {
    public:
        void DoStuff(BaseTest* test)
        {
            cout << "Whoo calling BaseTest to do stuff: " << test->GimmeNumber() << endl;
        }
    };

...

    class_<BaseTestWrap, boost::noncopyable>("BaseTest")
        .def("GimmeNumber", pure_virtual(&BaseTest::GimmeNumber))   // I have tried &BaseTestWrap here too.  Not sure what to do but it doesn't solve the issue at hand
        ;

    class_<ITakeFoo>("ITakeFoo", init<>())
        .def("DoStuff", &ITakeFoo::DoStuff)
        ;


In Python:
class DerivedTest(BaseTest):
    def __init__(self):
        pass

    def GimmeNumber(self):
        return 100

dt = DerivedTest()
ITF = ITakeFoo()
ITF.DoStuff(dt)

The DoStuff() call fails:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    ITakeFoo.DoStuff(ITakeFoo, DerivedTest)
did not match C++ signature:
    DoStuff(ITakeFoo {lvalue}, BaseTest*)

I can appreciate there being a memory-management-related policy issue but I can't see what might have to be done.  What else am I missing?  I guess I should add the documentation I've found would be nice to go this last mile and show how to do this step in the Boost documentation.  The wrapper stuff was fine enough but they don't see it getting called back into the native C++ code.

As it stands, if I do type.mro(DerivedTest), I see:
[<class '__main__.DerivedTest'>, <class 'BaseTest'>, <type 'Boost.Python.instance'>, <type 'object'>]

It appears to some extent it got it.

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

Re: Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

Nat Goodspeed-2
On Nov 12, 2011, at 11:34 AM, Adam Preble <[hidden email]> wrote:

> I am seeing this come up in many variations, with people doing slightly different things.

I have no direct experience with this issue myself, but I can parrot a bit of advice I've read here before.

> In Python:
> class DerivedTest(BaseTest):
>     def __init__(self):
        BaseTest.__init__(self)
>         pass
>
>     def GimmeNumber(self):
>         return 100
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

Adam Preble
Woooah that looks like it does work, although I had to interpret it like so:

class DerivedTest(BaseTest):
  def __init__(self):
    BaseTest.__init__(self)

  def GimmeNumber(self):
    return 100

I don't really consider myself an expert on these things, though I was Googling around on the proper way to handle the inheritance construction in Python.  Is this kind of the normal rigors when subclassing in Python normally, or is this something I must particularly pay attention to when using Boost?

On Sat, Nov 12, 2011 at 1:02 PM, Nat Goodspeed <[hidden email]> wrote:
On Nov 12, 2011, at 11:34 AM, Adam Preble <[hidden email]> wrote:

> I am seeing this come up in many variations, with people doing slightly different things.

I have no direct experience with this issue myself, but I can parrot a bit of advice I've read here before.

> In Python:
> class DerivedTest(BaseTest):
>     def __init__(self):
       BaseTest.__init__(self)
>         pass
>
>     def GimmeNumber(self):
>         return 100
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig


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

Re: Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

Jim Bosch-2
On 11/12/2011 02:12 PM, Adam Preble wrote:

> Woooah that looks like it does work, although I had to interpret it like so:
>
> class DerivedTest(BaseTest):
>    def __init__(self):
>      BaseTest.__init__(self)
>
>    def GimmeNumber(self):
>      return 100
>
> I don't really consider myself an expert on these things, though I was
> Googling around on the proper way to handle the inheritance construction
> in Python.  Is this kind of the normal rigors when subclassing in Python
> normally, or is this something I must particularly pay attention to when
> using Boost?
>

Calling the base class __init__ is less important in pure Python (i.e.
sometimes it's not necessary), but it's still definitely good practice;
it depends on whether the base class __init__ does anything important.
Python does not ever call it automatically, and in Boost.Python it
definitely does something important.

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

Re: Fwd: Passing Python-derived class back into a native C++ class doesn't match the C++ signature

Nat Goodspeed-2
On Nov 12, 2011, at 2:25 PM, Jim Bosch <[hidden email]> wrote:

> On 11/12/2011 02:12 PM, Adam Preble wrote:
>> Woooah that looks like it does work, although I had to interpret it like so:
>>
>> class DerivedTest(BaseTest):
>>   def __init__(self):
>>     BaseTest.__init__(self)

Yes, sorry the email quoting confused my intended indentation.

>> Is this kind of the normal rigors when subclassing in Python
>> normally, or is this something I must particularly pay attention to when
>> using Boost?
>
> Calling the base class __init__ is less important in pure Python (i.e. sometimes it's not necessary), but it's still definitely good practice; it depends on whether the base class __init__ does anything important. Python does not ever call it automatically, and in Boost.Python it definitely does something important.

That's right: this is NOT specific to Boost.Python. If your Python subclass constructor doesn't explicitly call the base-class constructor, the base class remains uninitialized. As Jim says, with Boost.Python the bad effect of an uninitialized base can include that type recognition failure.

fwiw, if the only logic in your subclass constructor is to forward all the same arguments to the base-class constructor, you could omit it entirely and just let Python implicitly call the inherited base-class constructor. I only define a subclass constructor when it must perform additional logic beyond initializing the base class. Again, that's a general rule in Python rather than anything specific to Boost.Python.
>
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig