[C++-sig] Problems with def(self_ns::str(self)) and virtual functions

John F Meinel Jr boost-users at johnmeinel.com
Tue Feb 10 04:13:54 CET 2004


I've been testing out boost::python for wrapping some C++ code that I've 
written, but I had some weird results trying to get the "__str__" 
functionality to work correctly.

I have a base C++ class that has a virtual function in it (with a 
default value). I derive another C++ class from it and change the 
virtual function.
I also create a std::ostream << operator so that I can print this class.

Here is the code:

struct Base {
	virtual ~Base() {}
	virtual int f() const { return 12345; }
};

struct Derived : Base {
	virtual int f() const { return 54321; }
};

inline int call_f(Base& b) { return b.f(); }

inline std::ostream& operator<<(std::ostream& os, const Base& b) {
	return os << "A: " << b.f() << std::endl;
}

///// Begin Python Wrapper
#include <boost/python.hpp>

using namespace boost::python;

struct BaseWrap : Base {
	BaseWrap(PyObject* self_)
		: self(self_)
	{ }
	BaseWrap(PyObject* self_, const Base& b)
		: self(self_)
		, Base(b)
	{ }
	int f() const { return call_method<int>(self, "f"); }
	int default_f() const { return Base::f(); }
	PyObject *self;
};

BOOST_PYTHON_MODULE(test2) {
	class_<Base, BaseWrap>("Base")
		.def("f", Base::f, BaseWrap::default_f)
		.def(self_ns::str(self))
	;
	class_<Derived, bases<Base> >("Derived")
	// Without this, it doesn't work
		.def(self_ns::str(self))
	;
	def("call_f", call_f);
}
///// End Python Wrapper

First, the Tutorial doesn't include the need for BaseWrap to have both 
constructors, but it wouldn't compile without both of them (I am using 
boost-1.31.0 with MSVC 2003 and python 2.3, though I am trying to get it 
all to work with GCC 3.2.2)

First, I can test that without the python wrapper, in a simple C++ 
script I can do
std::cout << Base() << std::endl;
and
std::cout << Derived() << std::endl;
and I get the correct output. So I know that in C++ the << operator is 
calling the appropriate overloaded function.

However, when I load this library in python, if I don't define 
.def(self_ns::str(self)) for the Derived class, it prints out the exact 
string for the Base().

Here is the exact python code that I type
 >>> import test2
 >>> import test2
 >>> b = test2.Base()
 >>> b.f()
12345
 >>> test2.call_f(b)
12345
 >>> print b
A: 12345

 >>> d = test2.Derived()
 >>> d.f()
54321
 >>> test2.call_f(d)
54321
 >>> print d
A: 12345

With __str__ redefined for the Derived class I get
 >>> print d
A: 54321

Which is what I want.
What is really weird is that call_f() works correctly in python, even if 
I derive a class in python.
 >>> class MyClass(test2.Base):
...     def f(self):
...             return 9876
...
 >>> m = MyClass()
 >>> m.f()
9876
 >>> test2.call_f(m)
9876
 >>> print m
A: 12345

Does anyone know why the call_f() operator is using the correct 
overload, but the __str__ operator isn't?

Thanks,
John
=:->





More information about the Cplusplus-sig mailing list