Hi all,
Thanks to previous help (a while ago) I was able to make considerable
progress wrapping a pretty complex library (OpenSceneGraph) with
boost.python. I've been working on this a bit more lately in my free
time, and I've been able to wrap pretty much everything I wanted to.
It's starting to look really good.
But I've got a problem overriding classes with python code. The
overridden method gets called, but when (from python code) it calls some
other C++ method using the arguments it was given, the arguments are
sliced to the base type.
I'll give some example code, but unfortunately I have to give a lot for
it to make sense... Sorry about that. The definitions below are just for
context:
class osg::Node
{
public:
//...
// does nothing in base class
virtual void traverse(NodeVisitor& nv) {}
// ...
};
class osg::Group
{
public:
//...
// overridden to traverse children
virtual void traverse(NodeVisitor& nv) {...}
// ...
};
class osg::NodeVisitor
{
public:
// ...
virtual void apply(osg::Node& node) { traverse(node); }
virtual void apply(osg::Group& node) {
apply(static_cast(node); }
// ... versions for other subclasses of osg::Node and osg::Group
inline void traverse(osg::Node& node)
{
// ...
node.traverse(*this);
}
// ...
}
This is a classic visitor double-dispatch implementation, which in C++
is used like this:
class DerivedVisitor : public osg::NodeVisitor
{
public:
DerivedVisitor() :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
// Override the version of apply you want to do the work.
void apply(osg::Node& node)
{
// ... Do something
// method must call traverse(node) to continue traversal.
traverse(node);
}
};
main()
{
osg::Group* g1 = new osg::Group;
g1->setName("g1");
osg::Group* g2 = new osg::Group;
g2->setName("g2");
g1->addChild(g2);
osg::Node* n = new osg::Node;
n->setName("n");
g2->addChild(n);
DerivedVisitor v;
g1->accept(v);
}
This will call apply(osg::Node&) 3 times, because the first two times,
traverse(node) will call osg::Group's version of traverse(NodeVisitor&)
which traverses its children. (note that NodeVisitor's default
implementation of apply(Group&) is to call apply(Node&) and the same for
all other subclasses which call their parent class's apply() )
Now, the problem I'm having with this in boost.python is that apply_Node
(which is the name I've given my wrapped apply(Node&) so that python
knows which version to call) is being called only once (at the
parent-most node). So it seems that it's osg::Node's version of
traverse(NodeVisitor&) that's being called since it's not traversing to
its children. I've got another example of this with NodeCallback, where
a method traverse(Node*) should traverse to its children, but it doesn't
and I can see that because if it did, a certain 3D model would get drawn
to the screen, but it doesn't (and it does if I remove my
python-overridden NodeCallback).
My wrapper code is mostly based on the example here:
http://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
struct NodeVisitor_wrapper : public NodeVisitor
{
// NodeVisitor constructors storing initial self parameter
NodeVisitor_wrapper(PyObject *p,
NodeVisitor::TraversalMode tm =
NodeVisitor::TRAVERSE_NONE)
: NodeVisitor(tm), self(p) {}
NodeVisitor_wrapper(PyObject *p, NodeVisitor::VisitorType type,
NodeVisitor::TraversalMode tm =
NodeVisitor::TRAVERSE_NONE)
: NodeVisitor(type, tm), self(p) {}
// In case NodeVisitor is returned by-value from a wrapped function
NodeVisitor_wrapper(PyObject *p, const NodeVisitor& x)
: NodeVisitor(x), self(p) {}
// Override apply to call back into Python
void apply(Node& node)
{
//std::cout << "in apply(Node&)" << std::endl;
try {
//std::cout << "Calling override" << std::endl;
call_method(self, "apply_Node", node);
}
// Catch boost::python exception, means method was not
// overridden in subclass.
catch (error_already_set) {
NodeVisitor::apply(node);
}
}
// Supplies the default implementation of apply
void default_apply_Node(NodeVisitor& self_, Node& node)
{
//std::cout << "in default_apply(Node&)" << std::endl;
self_.NodeVisitor::apply(node);
}
// Override apply to call back into Python
void apply(Group& node)
{
//std::cout << "in apply(Group&)" << std::endl;
try {
//std::cout << "Calling override" << std::endl;
call_method(self, "apply_Group", node);
}
// Catch boost::python exception, means method was not
// overridden in subclass.
catc