Extending classes written in C++ using SWIG

Jacek Generowicz jacek.generowicz at cern.ch
Thu Nov 25 10:25:22 EST 2004


tjordah at 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.



More information about the Python-list mailing list