[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