-
|
Hi, I'm running into what seems like unexpected behavior in nanobind regarding virtual dispatch. I have two C++ classes, a base class struct Shape {
virtual void draw(void){ std::cout << "Shape" << std::endl; };
};
struct Circle : public Shape {
void draw(void) { std::cout << "Circle" << std::endl; } override;
};I also have a function that takes a void call(std::shared_ptr<Shape> shape){
shape->draw();
}Bindings look like this: NB_MODULE(_bindings, m) {
m.def("create_circle", []() {
return std::make_shared<Circle>();
});
m.def("call", &call);
nb::class_<Shape>(m, "Shape")
.def("draw", &Shape::draw);
nb::class_<Circle, Shape>(m, "Circle")
.def("draw", &Circle::draw);
}Now, from Python: shape = create_circle()
shape.draw() # Outputs: "Circle"
call(shape) # Outputs: "Shape"This suggests that dynamic dispatch is lost when the object is passed back into C++. I also tested with raw pointers and the behaviour remains the same, i.e., Is there something I am missing in how nanobind handles dynamic type information for subclass instances passed into C++ functions? Thanks four your help! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
|
Cannot reproduce. I get Did you test your own C++ code? This does not even compile on my end, I had to change it to struct Shape {
virtual void draw(void){ std::cout << "Shape" << std::endl; };
virtual ~Shape() = default;
};
struct Circle : public Shape {
void draw(void) override { std::cout << "Circle" << std::endl; };
};
void call(std::shared_ptr<Shape> shape){
shape->draw();
}What I suspect is happening without knowning all details is that you are returning some other class, e.g. Either you get the type declared on the function interface, or the derived type if it has bindings. |
Beta Was this translation helpful? Give feedback.
Found the issue. I overlooked a third-party library call was slicing the
std::shared_ptr<Shape>passed tocall(). This made it seem as if the problem was in my bindings at first. Sorry about the confusion, closing this now.