[C++-sig] convert child class to child class {lvalue} ?

Steven Wyckoff steven.wyckoff at gmail.com
Wed Oct 10 23:53:06 CEST 2007


Hi all,

I am trying to wrap some C++ code that involves an object factory and 
manager and I seem to be stumped by how boost is converting types. I have a 
base class and a few classes that inherit from it and a factory to create 
instances of these classes. Using the factory I can successfully create 
objects of the proper type. Following the tutorial I have virtual functions 
behaving properly. However, if I try to call methods that only exist in a 
child class, I get an Argument Error:

ArgumentError: Python argument types in
    childobj.ChildOnly(childobj)
did not match C++ signature:
    ChildOnly(struct childobj {lvalue})

 I have tried writing a function that will cast the pointer to a child class 
pointer. This lets me call child only methods, but then i get the mirror 
error when I try to call base class methods. The confounding part is that it 
appears that the type information is correct in python.

If I create an instance without using the factory (child = childobj()) then 
everything works just fine.

I guess I could write converters to go both ways and just cast to whatever 
type I need for the current function call, but that is hardly ideal. If 
anyone has any suggestions about how I can get around this (maybe a type 
converter that I'm not aware of?) I would appreciate it.

Here is my code:


C++ code:
-----------------------------------------------------------------------
struct baseobj
{
    virtual std::string ID() {return std::string("BaseObj");}
    void SetVal(int v) {val = v;}
    int GetVal() {return val;}
    int val;
};

struct childobj : public baseobj
{
    virtual std::string ID() {return std::string("ChildObj");}
    std::string ChildOnly() {return "OK";}
};

baseobj* createobj(std::string kind)
{
    if(kind == "Base")
    {
        return new baseobj();
    }
    else if(kind == "Child")
    {
        return new childobj();
    }
    else
    {
        return NULL;
    }
}

childobj* CastToChild(baseobj* pobj)
{
    return static_cast<childobj*>(pobj);
}

struct BaseWrap : baseobj, boost::python::wrapper<baseobj>
{
    std::string ID()
    {
        if(boost::python::override f = this->get_override("ID"))
            return ID();
        return baseobj::ID();
    }
    std::string default_ID() {return this->baseobj::ID();}
};

BOOST_PYTHON_MODULE(extending)
{
using namespace boost::python;

class_<BaseWrap, boost::noncopyable>("baseobj")
.def("ID", &baseobj::ID, &BaseWrap::ID, "Returns the ID of the object")
.def("GetVal", &baseobj::GetVal)
.def("SetVal", &baseobj::SetVal)
;

class_<childobj, bases<BaseWrap> >("childobj")
.def("ChildOnly", &childobj::ChildOnly)
;

implicitly_convertible<childobj,baseobj>();
class_<objman>("objman")
.def("SetObj", &objman::SetObj)
.def("GetObj", &objman::GetObj, 
return_value_policy<reference_existing_object>())
;

def("create", &createobj, return_value_policy<manage_new_object>() );

def("callID", &callID );

def("CastToChild", &CastToChild, 
return_value_policy<reference_existing_object>());

}


Python:
----------------------------------------------------------------------------
>>> from extending import *
>>> base = create("Base")
>>> base.ID()
'BaseObj'
>>> child = create("Child")
>>> child.ID()
'ChildObj'
>>> child.ChildOnly()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    child.ChildOnly()
ArgumentError: Python argument types in
    childobj.ChildOnly(childobj)
did not match C++ signature:
    ChildOnly(struct childobj {lvalue})
>>> castchild = CastToChild(child)
>>> castchild.ChildOnly()
'OK'
>>> castchild.ID()
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    castchild.ID()
ArgumentError: Python argument types in
    baseobj.ID(childobj)
did not match C++ signature:
    ID(struct BaseWrap {lvalue})
    ID(struct baseobj {lvalue})






More information about the Cplusplus-sig mailing list