[C++-sig] call_back and inheritance

David Abrahams dave at boost-consulting.com
Sat Aug 3 14:12:03 CEST 2002


From: "Mike Owen" <mikeowen at speakeasy.net>


> Ah, I see what you're saying, and indeed when I remove the .def() from
the
> AbstractBase definitions I can correctly override and use the
AbstractBase
> from python.   Cool!
>
> However, I still don't see how I can get the ability to override the
method
> again in python classes that inherit from the Derived C++ class.


> I seem to
> be having trouble trying to define a call_back class for the Derived
class in
> this example, and therefore I have not been able to get a python method
to
> override it's methods.  How should we handle the wrapping of Derived so
we
> can override it's methods too?


Mike,

Rule #1 of support requests: provide a precise description of what you did,
what results you got, and what results you expected.
I don't see anything here that prevents you from overriding the
"pureVirtualMethod" of Python classes derived from Derived.

OK, looking more closely, I spy this line:

             .def("pureVirtualMethod", &AbstractBase::pureVirtualMethod)

virtual functions should basically never be exposed directly with .def().
If you want to expose the default implementation of a virtual function you
need to write a thin non-virtual wrapper over it, much as described in the
v1 docs (www.boost.org/libs/python/doc/overriding.html). The virtual
function overriding procedure has remained largely unchanged from v1.

HTH2,
Dave

> Thanks for the pointers!
>
> Mike.
>
> Here's the modified version of the previous example where I've removed
the
> .def for the pure virtual method from AbstractBase call_back again.
> #include <iostream>
> using namespace std;
>
> // BPL includes.
> #include "boost/python/class.hpp"
> #include "boost/python/module.hpp"
> #include "boost/python/call_method.hpp"
> using namespace boost::python;
>
>
//-------------------------------------------------------------------------
-----
> // Class definitions.
>
//-------------------------------------------------------------------------
-----
> class AbstractBase {
> public:
>   AbstractBase():
>     mInternalValue(-10) {}
>   virtual ~AbstractBase() {}
>   virtual void pureVirtualMethod() = 0;
>   virtual int processValue() = 0;
>
>   void printInternalValue() {
>     cout << "AbstractBase::InternalValue = " << mInternalValue << endl;
>   }
>
>   void callVirtualMethod() {
>     cout << "AbstractBase::callVirtualMethod()" << endl;
>     pureVirtualMethod();
>   }
>
>   int internalValue() {
>     return mInternalValue;
>   }
>
> private:
>   int mInternalValue;
> };
>
> class Derived: public AbstractBase {
> public:
>   Derived():
>     AbstractBase() {}
>   virtual ~Derived() {}
>
>   virtual void pureVirtualMethod() {
>     cout << "Derived::pureVirtualMethod()" << endl;
>     printInternalValue();
>   }
>
>   virtual int processValue() {
>     cout << "Derived::processValue()" << endl;
>     return 2*internalValue();
>   }
>
> };
>
>
//-------------------------------------------------------------------------
-----
> // Call back class to provide BPL overrides for AbstractBase.
>
//-------------------------------------------------------------------------
-----
> class AbstractBaseCallBack: public AbstractBase {
> public:
>   AbstractBaseCallBack(PyObject *self):
>     AbstractBase(),
>     mSelf(self) {}
>
>   void pureVirtualMethod() {
>     return call_method<void>(mSelf, "pureVirtualMethod");
>   }
>
>   int processValue() {
>     return call_method<int>(mSelf, "processValue");
>   }
>
> private:
>   PyObject* mSelf;
> };
>
>
//-------------------------------------------------------------------------
-----
> // Call back class to provide BPL overrides for Derived.
>
//-------------------------------------------------------------------------
-----
> class DerivedCallBack: public Derived {
> public:
>   DerivedCallBack(PyObject *self):
>     Derived(),
>     mSelf(self) {}
>
>   void pureVirtualMethod() {
>     return call_method<void>(mSelf, "pureVirtualMethod");
>   }
>
>   int processValue() {
>     return call_method<int>(mSelf, "processValue");
>   }
>
> private:
>   PyObject* mSelf;
> };
>
> // class DerivedCallBack: public Derived,
> //                        public AbstractBaseCallBack {
> // public:
> //   DerivedCallBack(PyObject *self):
> //     Derived(),
> //     AbstractBaseCallBack(self) {}
> // };
>
>
//-------------------------------------------------------------------------
-----
> // Helper methods to wrap the classes in this module.
>
//-------------------------------------------------------------------------
-----
> void wrapAbstractBase(module& mod) {
>   mod.add(class_<AbstractBase,
>            boost::shared_ptr<AbstractBaseCallBack>,
>                  boost::noncopyable>("AbstractBase")
>           .def_init()
>           .def("printInternalValue", &AbstractBase::printInternalValue)
>           .def("callVirtualMethod", &AbstractBase::callVirtualMethod)
>           );
> }
>
> void wrapDerived(module& mod) {
>     mod.add(class_<Derived,
>                    bases<AbstractBase>,
>                    boost::shared_ptr<DerivedCallBack>,
>                    boost::noncopyable>("Derived")
>             .def_init()
>             .def("pureVirtualMethod", &AbstractBase::pureVirtualMethod)
>             );
> }
>
>
//-------------------------------------------------------------------------
-----
> // The BPL wrapped python module.
>
//-------------------------------------------------------------------------
-----
> BOOST_PYTHON_MODULE_INIT(callback) {
>   module mod("callback");
>
>   // AbstractBase
>   wrapAbstractBase(mod);
>
>   // Derived
>   wrapDerived(mod);
>
> }







More information about the Cplusplus-sig mailing list