[C++-sig] to python conversion for derived facade

Moe Goldberg goldberg at coredp.com
Thu Apr 10 18:12:20 CEST 2008


Hi,
I don't have a lot of experience with boost, expecially not with 
to_python_converters, and I've been getting some unexpected results. I 
have spent a while looking around to see what I can find, but I can't 
seem to solve my problem, hopefully someone here can give me a hand.

Here's the situation. I have a facade class, and a class derived from 
it. The facade class is exposed to python but the derived class isn't 
(there are reasons for this, so exposing the derived class to python 
isn't an option). The derived class wraps a type (let's call it cpp_type 
- and it is also a type that I do not want exposed to python) that the 
base class does not.
I several functions that return a cpp_type_sptr (a smart pointer to 
cpp_type). I would like to create a to python converter so that I don't 
have to manually wrap each function that returns a cpp_type_sptr.
The to_python_converter that I wrote returns a facade to python instead 
of a facade_derived. As you will be able to see in the example (below) 
the facade_derived does get created properly in C++, but somehow when it 
gets passed to python, it gets converted to a facade.


I have simlpified the code (a lot) to create a small subset that 
highlights exactly the issue that I am having. Here it is.

C++ source code:

#include <boost/python.hpp>
#include <string>
#include <iostream>

using namespace boost::python;

class cpp_type
{
    public:
        cpp_type(std::string n="") : refcount(0), name_(n)
        {
        }
       
        std::string name()
        {
            return name_;
        }

    protected:
        friend class cpp_type_sptr;
        void ref()
        {
            ++refcount;
        }
       
        void unref()
        {
            if (--refcount <= 0)
            {
                // This is getting called twice. Instead of fixing the 
bug, I'm
                // going to ignore deletion, since it's not important to 
this
                // example
                //delete this;
            }
        }
       
        int refcount;
        std::string name_;
};

class cpp_type_sptr
{
    public:
        cpp_type_sptr():
            ptr_(NULL)
        {
           
        }
       
        cpp_type_sptr(cpp_type* ct):
            ptr_(ct)
        {
            if (ptr_)
            {
                ptr_->ref();
            }
        }
       
        virtual ~cpp_type_sptr()
        {
            if (ptr_)
            {
                ptr_->unref();
            }           
        }
       
        operator bool() const
        {
            return (ptr_ != (cpp_type*)0)? true : false;
        }
     
        bool operator!() const
        {
            return (ptr_ != (cpp_type*)0)? false : true;
        }
     
        cpp_type &operator * () const
        {
            return *ptr_;
        }
     
        cpp_type *operator -> () const
        {
            return ptr_;
        }

    private:
        cpp_type* ptr_;
};

struct facade
{
    facade()
    {
       
    }
   
    virtual std::string ct_name()
    {
        return "not telling";
    }

};

struct facade_derived : public facade
{
    facade_derived(cpp_type_sptr x)
    {
        if (x)
        {
            ct = *x;
        }
    }

    virtual std::string ct_name()
    {
        return ct.name();
    }
   
    cpp_type ct;
};

struct facade_wrapper : facade,boost::python::wrapper<facade>
{
    virtual std::string ct_name()
    {
        return this->get_override("ct_name")();
    }
};

facade * make_facade(cpp_type_sptr x = NULL)
{
    if (!x)
    {
        return new facade();
    }
    else
    {
        return new facade_derived(x);
    }
};

struct type_to_facade
{
    static PyObject* convert(cpp_type_sptr ct)
    {
        return incref(object(make_facade(ct)).ptr());
    }
};

cpp_type_sptr do_stuff(std::string s)
{
    cpp_type *ct = new cpp_type(s);
    std::cout << "from C++ ct_name -> " << ct->name() << std::endl;
    return cpp_type_sptr(ct);
}

BOOST_PYTHON_MODULE(mod)
{
    class_< facade >("facade", no_init);
    class_< facade_wrapper, boost::noncopyable >("facade")
        .def("name", &facade::ct_name)
        ;
       
    to_python_converter<cpp_type_sptr, type_to_facade>();
    def("do_stuff", do_stuff);  
}


using the python module:

 >>> from mod import *
 >>> g = do_stuff("some awesome name")
from C++ ct_name -> some awesome name
 >>> g.name()
'not telling'

As you can see, in C++ the object gets created correctly, but the python 
object does not.

Thanks in advance for any help.
-MG



More information about the Cplusplus-sig mailing list