[C++-sig] Re: call_method

David Abrahams dave at boost-consulting.com
Sun Nov 17 00:44:37 CET 2002


"Brett Calcott" <brett.calcott at paradise.net.nz> writes:

> Ok, make_shared() increments the PyObject refcount, and the pyobject deleter
> decrements it. But I still don't get the full picture -- can I put this back
> in the context of my project.

Let's try.

> Assumption: I have a c++ library and I want to layer the python stuff on top
> with minimal intrusion.

That's a Boost.Python design premise.

> It looks like this:
>
> class agent
> {
> public:
>     virtual void do_something()
>     {
>        cout << "in c++";
>     }
> };
> typedef shared_ptr<agent> agent_ptr;
> typedef vector<agent_ptr> agents;
>
> class engine
> {
>     agents m_agents;
> public:
>     void add_agent(agent_ptr const &a)
>     {
>         m_agents.push_back(a);
>     }
>
>     void do_stuff_with_agents()
>     {
>         for_each(m_agents.begin(), m_agents.end(),
> mem_fun(agent::do_something));
>     }
> };
>
> Note that I am using shared_ptr here for my own purpose *unrelated* to
> python implementation.

Yup. You probably want a virtual destructor in agent.

> Now, what do I need to do to expose my C++ lib to python and make
> agent::do_something overrideable in python code?

Just the usual stuff. Make a py_agent class like this:

struct agent_callback : agent
{
    agent_callback(PyObject* self) : m_self(self) {}

    void do_something() { call_method<void>(self, "do_something"); }

    // expose this as "do_something"
    static void default_do_something(agent& a)
     { a.agent::do_something(); } 

    PyObject* m_self;
};

        ...
        class<agent, agent_callback, ...>("agent")
           .def("do_something", &agent_callback::default_do_something)
           ;

> in python I want:
>
> from xxxx import *
> class py_agent(agent):
>    def do_something():
>       print 'in python'
>
> e = engine()
> e.add_agent(agent())
> e.add_agent(py_agent())
> e.do_stuff_with_agents()
>
> It seems I have to touch the source code

Why? How?

>  - so we are intruding on the c++
> lib. Not the best, but unavoidable in this situation I think. 

??

> The 'crazy pointer' solution required inheriting agent from a base
> class and adding a constructor with PyObject *. But we can easily
> use some #ifdef's to compile a pythonized-or-not version of the
> library.

Shouldn't be neccessary.

> Now the solution that you are proposing requires a call to
> make_shared. I'm not sure where this is happening. Does Boost.Python
> do it for me? 

Yes, or at least it will once we make the right changes.

> Am I required to call it whenever I need to access the
> elements in m_agents? 

No, why would you? Those are shared_ptr<agent>s.

> I can't see how the solution you have can work without causing me to
> change significantly the underlying c++ lib. Maybe I just don't get
> it yet.

HTH,

-- 
                       David Abrahams
   dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution





More information about the Cplusplus-sig mailing list