[C++-sig] In a C++ extension, how to use a C++ class exported in another extension

Clark foo.Clark at gmail.com
Thu Jun 30 17:05:41 CEST 2005


It takes much time of me to solve this problem.

The answer is: 
A class member named "this" is added to every python class wrapped by
SWIG. The "this" is a "PySwigObject", which has a member points to 
the C++ 'this' pointer. For example
A C++ class exposed by SWIG:
    class Foo
    {  
    public:
        virtual void foo()
        {
            printf("Foo bar!\n");
        }
    } 
A C++ function exposed by Boost.Python:
    void bar(PyObject *obj)
    { 
        PySwigObject *psObj = (PySwigObject *)obj;
        Foo *f = psObj->ptr;
        f->foo();
    } 
A Python script:
    >>>a = Foo()
    >>>bar(a.this)
    Foo bar!
    >>>

Here is another simple but complete example to illustrate the approach.

There are four files: foo.h, foo.cpp, foo.i, bar.cpp.
foo.h      is a C++ header file that declares a C++ class Foo, 
           which has a method "foo()".
foo.cpp    is a C++ source file that defines the method "Foo::foo()" 
foo.i      is a SWIG interface definition file that exposes 
           C++ class "Foo" to Python.
bar.cpp    is a C++ source file that makes use of Boost.Python 
           to expose a function "foobar".
foobar.py  is python script which will output "Foo bar!"

After building two python extension modules foo and bar 
by SWIG and Boost.Python, respectively, running the script foobar.py 
will give the output "Foo bar!"

================== foo.h ================
class Foo 
{
public:
   virtual void foo() const;
};
-----------------------------------------

================ foo.cpp ================
#include "foo.h"
#include <stdio.h>

void Foo::foo() const
{
    printf("Foo bar!\n");
}
-----------------------------------------

================= foo.i =================
%module foo 
%{
#include "foo.h"
%}

class Foo 
{
public:
    void foo() const;
};
-----------------------------------------

================ bar.cpp ================
#include <boost/python.hpp>    
using namespace boost::python; 
#include "foo.h"

typedef struct {
    PyObject_HEAD
    void *ptr;
    const char *desc;
} PySwigObject;

void foobar(object obj)       
{
    // convert obj to Foo *
    Foo *f = (Foo *)(((PySwigObject *)obj.ptr())->ptr);
    f->foo();
}

BOOST_PYTHON_MODULE(bar)     
{
    def("foobar", &foobar);      
}
-----------------------------------------

=============== foobar.py ===============
import foo, bar
a = foo.Foo()
bar.foobar(a.this)
-----------------------------------------




On Thu, May 19, 2005 at 11:29:17AM -0400, David Abrahams wrote:
> The following message is a courtesy copy of an article
> that has been posted to gmane.comp.python.c++ as well.
> 
> Clark <foo.Clark at gmail.com> writes:
> 
> > We know that cross-module type info share is easy with latest Swig or
> > Boost.Python.
> > But how to make it possible to do with Swig and Boost.Python together?
> >
> > For example, we have two c++ extension A and B, which are exposed
> > with Swig and Boost.Python, respectively. They are as follows:
> >
> > ==============Module A wrapped with Swig ===============
> >    class Base
> > {
> > public:
> >         Base();
> >             ...
> > };
> > --------------------------------------------------------
> >
> > ========== Module B wrapped with Boost.Python ==========
> > void foo(Base *);
> >
> > class Derive: public Base
> > {
> >         ...
> > };
> > --------------------------------------------------------
> >
> > I wish to use module A and B in Python like this:
> >
> > ============= Module A and B used in Python ============
> >>>>import A
> >>>>import B
> >>>>obj = A.Base()
> >>>>B.foo(obj)
> >>>>obj = B.Derive()
> >>>>B.foo(obj)
> > --------------------------------------------------------
> >
> > Could anybody give me a solution or some hints? I've working for
> > this for long.
> 
> Well, you can use the raw converter stuff, which is documented in
> http://www.boost.org/libs/python/doc/v2/reference.html#type_conversion.
> You might also see the test code that exercises these facilities in
> libs/python/test/m1.cpp, libs/python/test/m2.cpp, and
> libs/python/test/newtest.py.  
> 
> If SWIG is generating a Python extension type object BaseType, and an
> extension instance type BaseObject corresponding to Base, you could
> use lvalue_from_pytype, something like:
> 
>   lvalue_from_pytype<extract_member<
>         BaseObject, Base, &BaseObject::value>,&BaseType>();
> 
> Otherwise, you'll have to touch some ugly, undocumented details of
> Boost.Python.  Let me know if you need that, and I'll try to help.
> 
> HTH,
> -- 
> Dave Abrahams
> Boost Consulting
> www.boost-consulting.com



More information about the Cplusplus-sig mailing list