[C++-sig] Still unsolved: Embedded python and pure virtual functions

Birgir Sigurjonsson birgir-s at online.no
Fri Jan 5 21:02:41 CET 2007


Hei all, I am still struggeling with my embedded python where I am trying to employ
the abstract factory pattern to do some plugins.

I have packed my code in the embedded example from the libs/python directory
so it is only on file and not that long.

My problem is that the make function in the BaseFactory is returning a pointer
to a Base  (the make function is pure virtual). Therefore I think my BaseFactoryWrap
is wrong. I have tried various ways but I have failed in every way.

I am not C++ nor Python expert, but the question is I think,

How can I wrap my pure virtual BaseFactory::make to return pointer to Base
that I can use to call a pure virtual function Base::hello that is defined in 
Python class (PythonDerived) that inherites Base.

Best regards,
Birgir Sigurjonsson.

////// clipp and compile (linux)
#include <boost/python.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <stdexcept>
#include <cassert>

namespace python = boost::python;

// An abstract base class
class Base : public boost::noncopyable
{
public:
     Base() {std::cout << "constructor Base\n"; }
     virtual ~Base() {std::cout << "destructor Base::~Base\n"; };

     virtual std::string hello() = 0;
};

// An abstract base factirt class
class BaseFactory : public boost::noncopyable
{
public:
     BaseFactory(const std::string& key);
     virtual ~BaseFactory();
     static boost::shared_ptr<Base> create(const std::string &key);
     virtual  Base * make() = 0;
     std::string m_key;
     static BaseFactory * m_base_factory;
};

BaseFactory * BaseFactory::m_base_factory = NULL;

// An abstract base factory class
BaseFactory::BaseFactory(const std::string& key) {
   std::cerr << "BaseFactory::BaseFactory register base class: " << key << "\n";
   m_base_factory = this;
   m_key = key;
}

BaseFactory::~BaseFactory() {
}

boost::shared_ptr<Base>
BaseFactory::create (const std::string &key) {
   std::cout << "Creating Base = "<< key << "\n";
   Base * a = m_base_factory->make();
   boost::shared_ptr<Base> concrete_loader(a);

   return concrete_loader;
}

// Familiar Boost.Python wrapper class for Base
struct BaseWrap : public Base, public python::wrapper<Base>
{
     BaseWrap(PyObject* self_) : self(self_) {Py_INCREF(self);}
     virtual ~BaseWrap () { Py_DECREF(self); }
     std::string hello() {return this->get_override("hello")(); }
     PyObject* self;
};

class BaseFactoryWrap : public BaseFactory, public python::wrapper<BaseFactory> {
public:
   BaseFactoryWrap(const std::string& key) : BaseFactory(key) {}
   Base* make() {    return this->get_override("make")();  }
};

// Pack the Base and BaseFactory classes wrappers into a module
BOOST_PYTHON_MODULE(embedded_hello)
{
     python::class_<Base, BaseWrap, boost::noncopyable>("Base")
       .def("hello",  python::pure_virtual(&Base::hello))
         ;

     python::class_<BaseFactoryWrap, boost::noncopyable>("BaseFactory", python::init<std::string>())
         .def("make",  python::pure_virtual(&BaseFactory::make), python::return_value_policy<python::manage_new_object>())
     ;
}

void test()
{
//- INITIALIZATION -----------------------------------------------------------//
     // Register the module with the interpreter
     if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1)
         throw std::runtime_error("Failed to add embedded_hello to the interpreter's "
                                  "builtin modules");
     // Retrieve the main module
     python::object main_module((
         python::handle<>(python::borrowed(PyImport_AddModule("__main__")))));

     // Retrieve the main module's namespace
     python::object main_namespace((main_module.attr("__dict__")));

     // Define the derived class in Python.
     // (You'll normally want to put this in a .py file.)
     python::handle<> result(
         PyRun_String(
         "from embedded_hello import *\n"
         "class PythonDerived(Base):\n"
         "    def __init__(self):\n"
         "        super(PythonDerived, self).__init__()\n"
         "        print self.__init__             \n"
         "    def hello(self):                \n"
         "        return 'BIG HELLO, Hello from Python!' \n"
         "class PythonDerivedFactory(BaseFactory):\n"
         "    def __init__(self, key):\n"
         "        super(PythonDerivedFactory, self).__init__(key)\n"
         "        print  'Python running: 4--> PythonDerivedFactory(BaseFactory) __init__'\n"
         "        print self.__init__\n"
         "    def make(self):\n"
         "        print  'Python running: 5--> PythonDerivedFactory::make'\n"
         "        return PythonDerived()\n"
         "register_this = PythonDerivedFactory('Ascii135')\n"
         ,
         Py_file_input, main_namespace.ptr(), main_namespace.ptr())
         );
     // Result is not needed
     result.reset();

//- MAIN PROGRAM -------------------------------------------------------------//
     boost::shared_ptr<Base> a135 = BaseFactory::create("Ascii135");
     a135->hello();
}

int main()
{
     // Initialize the interpreter
     Py_Initialize();
     if (python::handle_exception(test))
     {
         if (PyErr_Occurred())
             PyErr_Print();
         return 1;
     }
     return 0;
}



More information about the Cplusplus-sig mailing list