Extending classes written in C++ using SWIG

Phil Thompson phil at riverbankcomputing.co.uk
Thu Nov 25 11:39:50 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.

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




More information about the Python-list mailing list