Menu

#957 %extend overridden method not inherited

open
nobody
python (260)
5
2024-07-18
2008-10-16
No

When using %extend to "reimplement" a virtual class method in class C, this reimplemented method is not available in subclass D of C but instead behaves as the original method.

E.g. (see attached tarball for these files)

=== classes.h ===

class C
{
public:
virtual void return_float(float &f) { f = 123; }
};

class D : public C
{
public:
virtual void return_float(float &f) { f = 456; }
};

=== test.i ===

%module(directors="1") test;

%{
#include "classes.h"
%}

%include "classes.h";

%extend C
{
// Pythonic way of returning a float
PyObject* return_float()
{
float f;
$self->return_float(f);
return Py_BuildValue("f", f);
}
};

When run through swig -c++ -python and GCC 4.1.2 the following then happens:

Python 2.5.2 (r252:60911, Oct 16 2008, 21:18:49)
[GCC 4.1.2 (Gentoo 4.1.2 p1.1)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> c = test.C()
>>> c.return_float()
123.0
>>> d = test.D()
>>> d.return_float()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 82, in return_float
def return_float(*args): return _test.D_return_float(*args)
TypeError: D_return_float() takes exactly 2 arguments (1 given)
>>>

This used to work (at least in 1.3.29)...

Discussion

  • Paul E.C. Melis

    Paul E.C. Melis - 2008-10-16

    Test case

     
  • Paul E.C. Melis

    Paul E.C. Melis - 2008-10-16

    Forgot to mention that this is with 1.3.36

     
  • Olly Betts

    Olly Betts - 2022-03-20

    Reproducible with current git master.

    Arguably a better way to achieve what you want here is to apply an OUTPUT typemap (which also eliminates the non-pythonic wrapping):

    %module(directors="1") test;
    
    %include <typemaps.i>
    %apply float* OUTPUT {float &f};
    %{
    #include "classes.h"
    %}
    
    %include "classes.h";
    

    However, I don't see why your example shouldn't work (there are some limitations with %extend and virtual methods - e.g. see https://github.com/swig/swig/issues/503#issuecomment-171447199 but here the method added isn't even virtual).

     
  • Olly Betts

    Olly Betts - 2024-07-18

    Reproduced with current git master (6eb2560e8d7192a8302e90ca3426df9aceb6d2e2).

    I noticed that if we ignore the methods we don't want then it works - e.g. add this before the %include "classes.h";:

    %ignore return_float(float &f);
    

    This is at least consistent with how method hiding would work if the %extend method was actually added in C++, consider this:

    #include <iostream>
    
    class C
    {
    public:
    virtual void return_float(float &f) { f = 123; }
    float return_float() { float f; return_float(f); return f; }
    virtual ~C() {}
    };
    
    class D : public C
    {
    public:
    virtual void return_float(float &f) { f = 456; }
    };
    
    int main() {
        D d;
        std::cout << d.return_float();
    }
    

    which fails to compile because D doesn't inherit float return_float() from C:

    $ g++ -Wall -W testhiding.cc 
    testhiding.cc: In function ‘int main()’:
    testhiding.cc:19:32: error: no matching function for call to ‘D::return_float()   19 |     std::cout << d.return_float();
          |                  ~~~~~~~~~~~~~~^~
    testhiding.cc:14:14: note: candidate: ‘virtual void D::return_float(float&)   14 | virtual void return_float(float &f) { f = 456; }
          |              ^~~~~~~~~~~~
    testhiding.cc:14:14: note:   candidate expects 1 argument, 0 provided
    

    I don't think that's why this doesn't work in SWIG though.

     

Log in to post a comment.

MongoDB Logo MongoDB