By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,870 Members | 1,212 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,870 IT Pros & Developers. It's quick & easy.

Extending classes written in C++ using SWIG

P: n/a
Im trying to extend a class written in C++ in Python and use this
extended class in a C++ call... I made an example to clarify:

-- Foo.h --
#ifndef FOO_H
#define FOO_H

#include <iostream>
using namespace std;

class Foo;
class Bar;

class Bar
{
public:
Bar() {};
~Bar() {};
virtual char* DoBar() const { return "Bar"; };
};

class Foo
{
public:
Foo() {};
~Foo() {};
virtual void DoFoo(Bar* someBar) { cout << someBar->DoBar() << endl;
};
};

#endif

-- Foo.cpp --
#include "Foo.h"

-- swig.i --
%module test
%{
#include "Foo.h"
%}

%include "Foo.h"

-- UseFoo.py --
#!/usr/bin/env python

from test import *;

class ExtendedBar(Bar):
def __init__(self):
Bar.__init__(self);

def DoBar(self):
return "ExtendedBar";

bar = ExtendedBar();
foo = Foo();
foo.DoFoo(bar);

------------

I now expect to get "ExtendedBar" as output from UseFoo.py (since I've
declared DoBar() as virtual, but I get "Bar".... I'm using SWIG 1.3.1
to create the bindings from Python to C++. (swig -python -c++)

Can anyone tell me why? Is there a way to remedy this??

Thx,
Lars Moastuen
Jul 18 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
tj*****@start.no (Lars Moastuen) writes:
class Bar
{
public:
Bar() {};
~Bar() {};
virtual char* DoBar() const { return "Bar"; };
};

class Foo
{
public:
Foo() {};
~Foo() {};
virtual void DoFoo(Bar* someBar) { cout << someBar->DoBar() << endl;
};
}; class ExtendedBar(Bar):
def __init__(self):
Bar.__init__(self);

def DoBar(self):
return "ExtendedBar";

bar = ExtendedBar();
foo = Foo();
foo.DoFoo(bar); I now expect to get "ExtendedBar" as output from UseFoo.py (since I've
declared DoBar() as virtual, but I get "Bar" Can anyone tell me why?
Because "someBar->DoBar()" uses the vtable of the C++ dynamic type to
decide which actual DoBar method to call. Unfortunately there is no
C++ type corresponding to your ExtendedBar, there is no vtable for
your ExtendedBar type in C++. C++ only knows about C++ types; it is
unaware of the existence of Python types. Inside your Python instance
of ExtendedBar you are holding on to an instance of a C++ Bar.
Is there a way to remedy this??


I don't know whether SWIG provides a boxed solution for this sort of
problem. One approach is to override the DoBar method in a subclass of
Bar in C++, and make that method pass the 'dispatch request' up into
Python. Then you expose the wrapper class in Python, rather than Bar
itself.

It looks something like this:

struct PseudoBar : public Bar {
PyObject* self; // the Python instance wrapping this C++ instance
void DoFoo () {
PyObject_CallMethod(this->self, "DoFoo", "");
}
};

Of course, you'll need to augment this with checks to ensure that
there really is something overriding the method, otherwise you'll end
up in an infinite loop ... but hopefully you get the idea. It's all a
bit tedious.
Jul 18 '05 #2

P: n/a
> tj*****@start.no (Lars Moastuen) writes:
class Bar
{
public:
Bar() {};
~Bar() {};
virtual char* DoBar() const { return "Bar"; };
};

class Foo
{
public:
Foo() {};
~Foo() {};
virtual void DoFoo(Bar* someBar) { cout << someBar->DoBar() << endl;
};
};

class ExtendedBar(Bar):
def __init__(self):
Bar.__init__(self);

def DoBar(self):
return "ExtendedBar";

bar = ExtendedBar();
foo = Foo();
foo.DoFoo(bar);

I now expect to get "ExtendedBar" as output from UseFoo.py (since I've
declared DoBar() as virtual, but I get "Bar"

Can anyone tell me why?


Because "someBar->DoBar()" uses the vtable of the C++ dynamic type to
decide which actual DoBar method to call. Unfortunately there is no
C++ type corresponding to your ExtendedBar, there is no vtable for
your ExtendedBar type in C++. C++ only knows about C++ types; it is
unaware of the existence of Python types. Inside your Python instance
of ExtendedBar you are holding on to an instance of a C++ Bar.
Is there a way to remedy this??


I don't know whether SWIG provides a boxed solution for this sort of
problem. One approach is to override the DoBar method in a subclass of
Bar in C++, and make that method pass the 'dispatch request' up into
Python. Then you expose the wrapper class in Python, rather than Bar
itself.

It looks something like this:

struct PseudoBar : public Bar {
PyObject* self; // the Python instance wrapping this C++ instance
void DoFoo () {
PyObject_CallMethod(this->self, "DoFoo", "");
}
};

Of course, you'll need to augment this with checks to ensure that
there really is something overriding the method, otherwise you'll end
up in an infinite loop ... but hopefully you get the idea. It's all a
bit tedious.


If SWIG really requires you to do this by hand (I'm surprised) then you
might want to look at SIP (http://www.riverbankcomputing.co.uk/sip/). SIP
generates code that does exactly what you suggest so that bindings behave
as the OP was expecting.

Phil

Jul 18 '05 #3

P: n/a
Thx for your replies.

It seems I have created an example I thought were equal to my problem,
but it turned out that wasn't the case. I'm trying to figure out what
the difference is, but I find the classes quite similar to the example
below (too big to post here)... However, this problem can be solved by
using "directors" (http://www.swig.org/Doc1.3/Python.html#directors),
mine cannot...

Im currently testing if Boost.Python does the job better, but seems I
run into the same problem... I suspect it has something to do with STL
list or something, but I'm not sure yet...

Will post if I manage to create an example or if I find a solution.
"Phil Thompson" <ph**@riverbankcomputing.co.uk> wrote in message news:<ma**************************************@pyt hon.org>...
tj*****@start.no (Lars Moastuen) writes:
class Bar
{
public:
Bar() {};
~Bar() {};
virtual char* DoBar() const { return "Bar"; };
};

class Foo
{
public:
Foo() {};
~Foo() {};
virtual void DoFoo(Bar* someBar) { cout << someBar->DoBar() << endl;
};
}; class ExtendedBar(Bar):
def __init__(self):
Bar.__init__(self);

def DoBar(self):
return "ExtendedBar";

bar = ExtendedBar();
foo = Foo();
foo.DoFoo(bar); I now expect to get "ExtendedBar" as output from UseFoo.py (since I've
declared DoBar() as virtual, but I get "Bar" Can anyone tell me why?


Because "someBar->DoBar()" uses the vtable of the C++ dynamic type to
decide which actual DoBar method to call. Unfortunately there is no
C++ type corresponding to your ExtendedBar, there is no vtable for
your ExtendedBar type in C++. C++ only knows about C++ types; it is
unaware of the existence of Python types. Inside your Python instance
of ExtendedBar you are holding on to an instance of a C++ Bar.
Is there a way to remedy this??


I don't know whether SWIG provides a boxed solution for this sort of
problem. One approach is to override the DoBar method in a subclass of
Bar in C++, and make that method pass the 'dispatch request' up into
Python. Then you expose the wrapper class in Python, rather than Bar
itself.

It looks something like this:

struct PseudoBar : public Bar {
PyObject* self; // the Python instance wrapping this C++ instance
void DoFoo () {
PyObject_CallMethod(this->self, "DoFoo", "");
}
};

Of course, you'll need to augment this with checks to ensure that
there really is something overriding the method, otherwise you'll end
up in an infinite loop ... but hopefully you get the idea. It's all a
bit tedious.


If SWIG really requires you to do this by hand (I'm surprised) then you
might want to look at SIP (http://www.riverbankcomputing.co.uk/sip/). SIP
generates code that does exactly what you suggest so that bindings behave
as the OP was expecting.

Phil

Jul 18 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.