user8510613
user8510613

Reputation: 1282

How to export c++ class adopted template method pattern with virtual interface to python world by pybind11?

We have a class hierarchy which follow the template method pattern. The Interface class has a pure virtual method process(). class AbstractImpl inherit it and fill the process body with some pure virtual stepX method. Finally, derived class Concrete1 implement those stepX method to extend custom behaviors.

class Interface {
public:
   virtual int process() = 0;
};

class AbstractImpl : public Interface {
public:
   int process override(){
       step1();
       // do something
       step2();
   }
protected:
    virtual void step1() = 0;
    virtual void step2() = 0;
};

class Derived : public AbstractImpl {
protected:
    void step1() final {
        // do something
    }

    void step2() final {
        // do something
    }
};

In c++ world, i can use easily it like:

Interface* obj = new Derived();
int res = obj->process();

Now we need to create some python binding for Derived class for some scaffolding test usage by pybind11. Ideally, in python world we could write:

obj = Derived()
res = obj.process()

I've checked the pybind11 document class section, which provide some examples like PYBIND11_OVERRIDE_PURE.

However, the Derived class actually not derived directly from Interface class, and we only want to export the base process method but not other protected step method to python world.

I wonder is there anyway to export the Derived class and it public interface process to python world, without much instruive code like PYBIND11_OVERRIDE_PURE added?

Upvotes: 0

Views: 166

Answers (1)

pptaszni
pptaszni

Reputation: 8312

If you only want to use your Derived class in your python code like this

obj = Derived()
res = obj.process()

it is just enough to export it to python as Derived class with AbstractImpl parent class and only one method process:

PYBIND11_MODULE(examplePythonModule, m) {
    py::class_<AbstractImpl>(m, "AbstractImpl")
        // no "init" for abstract class
        .def("process", &AbstractImpl::process);
    py::class_<Derived, AbstractImpl>(m, "Derived")
        .def(py::init<>());
        // process method already exported by the parent class
}

Add some observable behavior and check that it works. As long as you don't export any functions taking Interface& as argument, python doesn't even need to know about this type.

Upvotes: 1

Related Questions