@amastrobera Can you go into a bit more detail? What is the error/problem you get, and what is the code you have that results in that error?
The method in your trampoline class should be public. Otherwise pybind11's code cannot access it. See also here: https://pybind11.readthedocs.io/en/stable/advanced/classes.html#binding-protected-member-functions
(Note that there's also the Gitter chatbox for quick questions. You'll often get a quicker answer there.)
Hi @YannickJadoul
thank you for your kind attention. I give you a sample of code, don't have the respective error yet
#include <iostream>
class Animal {
public:
~Animal() = default;
std::string talk() { return makesound(); }
private:
virtual std::string makesound() = 0;
};
class Dog : public Animal {
private:
std::string makesound() override { return "woof!"; }
};
int main() {
Animal* p = new Dog();
std::cout << p->talk() << std::endl;
delete p;
return 0;
}
classic c++ case. if you compile and run it, it returns
$ g++ -I. main.cpp && ./a.out
woof!
note: I use g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
how do I convert it in pybind11 ?
@amastrobera If you just want to call talk() from Python, it's just as the docs say:
PYBIND11_MODULE(example, m) {
py::class_<Animal> animal(m, "Animal")
.def("talk", &Animal::talk);
py::class_<Dog, Animal>(m, "Dog")
.def(py::init<>());
}
If you want to be able to override the virtual function from Python, you need to do a bit of extra effort and create a trampoline class (cfr. docs as well):
class PyAnimal : public Animal {
public:
using Animal::Animal;
std::string makesound() override { PYBIND11_OVERLOAD_PURE(std::string, Animal, makesound); }
};
PYBIND11_MODULE(example, m) {
py::class_<Animal, PyAnimal> animal(m, "Animal")
.def(py::init<>())
.def("talk", &Animal::talk);
py::class_<Dog, Animal>(m, "Dog")
.def(py::init<>());
}
(And if you want to be able to subclass Dog in Python, you'll need to make a trampoline class for Dog as well; see https://pybind11.readthedocs.io/en/stable/advanced/classes.html#combining-virtual-functions-and-inheritance)
The main thing to note is that the makesound method of PyAnimal is public. Otherwise, C++ won't let pybind11 access it (since pybind11 is not a part of the Animal class).
Hi @YannickJadoul, thanks again. I can give you a better example now of what I am doing, still with "animals". this is my folder. please add "pybind11" directory inside, and build it as usual (mkdir build && cd build && cmake .. && make -j6). It compiles and runs in c++ (executable cppexample) but if you uncomment the pybind build part in the CMakeLists.txt, it doesn't work.
can you help me there?
This is the code
class Animal {
public:
Animal(std::string const& type="") : mType(type) {}
~Animal() = default;
std::string type() { return mType; }
std::string talk() { return makesound(); }
private:
virtual std::string makesound() = 0;
std::string mType;
};
class Dog : public Animal {
public:
Dog() : Animal("dog") {}
private:
std::string makesound() override { return "woof!"; }
};
PYBIND11_MODULE(pyexample, m) {
py::class_<Animal> animal(m, "Animal");
animal
.def(py::init<>())
.def("talk", &Animal::talk);
py::class_<Dog, Animal>(m, "Dog")
.def(py::init<>());
}
This is the error :
pybind11/include/pybind11/detail/init.h:63:64: error: invalid new-expression of abstract class type ‘example::Animal’
inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
@YannickJadoul never mind actually. my stupid mistake. I was exposing a constructor for a pure virtual function in python, which made no sense. I removed .def(py::init<>()) from Animal and all worked
Great you found the problem! Thanks for letting me know what went wrong :-)
Most helpful comment
@YannickJadoul never mind actually. my stupid mistake. I was exposing a constructor for a pure virtual function in python, which made no sense. I removed
.def(py::init<>())fromAnimaland all worked