Inheriting Base from C++ in Python, call abstract method using SWIG
<p>I'm having some trouble coupling C++ (98) with python 3. I have some base classes in C++ which I'd like to extend in Python. Some methods in question are pure virtual on the C++ side and will thus be implemented on the Python side.</p>

<p>Currently, I can call the abstract methods from C++ and, over swig, the specialization gets called in Python. Cool. I'm having trouble handing over parameters to Python..</p>

<p>Minimal complete example to simplify my problem:</p>

<pre><code>// iBase.h
#pragma once
#include &lt;memory&gt;

typedef enum EMyEnumeration{
    EMyEnumeration_Zero,
    EMyEnumeration_One,
    EMyEnumeration_Two

}TEMyEnumeration;


class FooBase{
protected:  
    int a;
public:
    virtual int getA() = 0 ; 
};

class Foo : public FooBase{
public:
    Foo() {a = 2;}
    int getA(){return a;}
};

class iBase{
    public:

    virtual void start() =0;
    virtual void run(std::shared_ptr&lt;FooBase&gt; p, TEMyEnumeration enumCode) = 0;
};
</code></pre>

<p>On the swig side: </p>

<pre><code>// myif.i
%module(directors="1") DllWrapper

%{
#include &lt;iostream&gt;
#include "iBase.h"
%}

%include &lt;std_shared_ptr.i&gt;
%shared_ptr(FooBase)
%shared_ptr(Foo)
%feature("director") FooBase;
%feature("director") iBase;
%include "iBase.h"
</code></pre>

<p>Run swig as:</p>

<pre><code>swig -c++ -python myif.i
swig -Wall -c++ -python -external-runtime runtime.h
</code></pre>

<p>Compile myif_wrap.cxx -> _DllWrapper.pyd </p>

<p>Create an *.exe with the following code, it will load up the _DllWrapper.pyd library (make sure it's in the same directory!). Also, copy DllWrapper.py generated by swig to the exe directory.</p>

<pre><code>//Main_SmartPtr.cpp
#include "stdafx.h"
#include &lt;Python.h&gt;
#include &lt;windows.h&gt; 
#include &lt;string&gt;
#include &lt;memory&gt;
#include "iBase.h"
#include "runtime.h"
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    string moduleName = "ExampleSmartPtr";

    // load *.pyd  (actually a dll file which implements PyInit__&lt;swigWrapperName&gt;)
    auto handle =LoadLibrary("_DllWrapper.pyd");

    // getting an instance handle..
    Py_Initialize();
    PyObject *main = PyImport_AddModule("__main__");
    PyObject *dict = PyModule_GetDict(main);

    PyObject *module = PyImport_Import(PyString_FromString(moduleName.c_str()));
    PyModule_AddObject(main, moduleName.c_str(), module);
    PyObject *instance = PyRun_String(string(moduleName+string(".")+moduleName+string("()")).c_str(), Py_eval_input, dict, dict);


    //calling start() in the Python derived class..
    //PyObject *result = PyObject_CallMethod(instance, "start", (char *)"()");

    // trying to call run in the Python derived class..

    shared_ptr&lt;Foo&gt; foo = make_shared&lt;Foo&gt;();
    EMyEnumeration enumCode = EMyEnumeration_Two;


    string  typeName1 = "std::shared_ptr &lt;FooBase&gt; *"; 
    swig_type_info* info1 = SWIG_TypeQuery(typeName1.c_str());
    auto swigData1 = SWIG_NewPointerObj((void*)(&amp;foo), info1, SWIG_POINTER_OWN);

    string  typeName2 = "TEMyEnumeration *"; 
    swig_type_info* info2 = SWIG_TypeQuery(typeName2.c_str());
    auto swigData2 = SWIG_NewPointerObj((void*)(&amp;enumCode), info2, SWIG_POINTER_OWN);

    auto result = PyObject_CallMethod(instance, "run", (char *)"(O)(O)", swigData1, swigData2);

    return 0;
}
</code></pre>

<p>Create a new Python file and put it in the exe's directory: </p>

<pre><code>#ExampleSmartPtr.py
import DllWrapper

class ExampleSmartPtr(DllWrapper.iBase):
    def __init__(self): # constructor
        print("__init__!!")
        DllWrapper.iBase.__init__(self)

    def start(self):
        print("start")
        return 0

    def run(self, data, enumCode):
        print("run")
        print("-&gt; data: "+str(data))
        print("-&gt; enumCode: "+str(enumCode))

        print (data.getA())
        return 1
</code></pre>

<p>The output of running the exe is :</p>

<pre><code>__init__!!
run
-&gt; data: (&lt;DllWrapper.FooBase; proxy of &lt;Swig Object of type 'std::shared_ptr&lt; FooBase &gt; *' at 0x00000000014F8B70&gt; &gt;,)
-&gt; enumCode: (&lt;Swig Object of type 'TEMyEnumeration *' at 0x00000000014F89F0&gt;,)
</code></pre>

<p>How can one 'dereference' the enumCode to a simple int? How does one call print (data.getA()) in python class run()? In its current form it doesn't print anything..</p>

<p>This is not really an answer, but I read the discussion <a href="https://bytes.com/topic/python/answers/38519-extending-classes-written-c-using-swig" rel="nofollow">Discussion from 2005</a> and it makes sense, that it shouldn't be possible. If you on the Python side, do the following, you get your enumeration 'dereferenced' to a simple integer.</p>

<pre><code>import ExampleSmartPtr

instance = ExampleSmartPtr.ExampleSmartPtr()
swigData1 = ExampleSmartPtr.DllWrapper.Foo()
swigData2 = ExampleSmartPtr.DllWrapper.EMyEnumeration_Two
instance.run(swigData1,swigData2)
</code></pre>

<p>This will print</p>

<pre><code>__init__!!
run
-&gt; data: &lt;DllWrapper.Foo; proxy of &lt;Swig Object of type 'std::shared_ptr&lt; Foo &gt; *' at 0x7f8825c0b7e0&gt; &gt;
-&gt; enumCode: 2
</code></pre>

<p>I think that the issue is that two different vtables are into play. The original C++ vtable and that of the <code>Swig Object</code>. Just curious, in what scenario is it of interest to use a Python descendant of a C++ class from within C++?</p>

python c++ swig