Opened 20 years ago
Closed 16 years ago
#138 closed Support Requests (Fixed)
problem with overridable virtual functions in Boost.Python
| Reported by: | nobody | Owned by: | david_abrahams |
|---|---|---|---|
| Milestone: | Component: | python USE GITHUB | |
| Version: | None | Severity: | |
| Keywords: | Cc: |
Description
I'm having problems overriding functions in Python with
Boost. The examples provided on the website seem to work.
However, all the examples I have managed to find have
involved callback classes with virtual function overrides
having zero arguments. I am trying to override functions
with multiple arguments with no success. I get consistent
errors when trying to manipulate multi-argument virtual
functions polymorphically from a C++ extension. Im
currently using Visual Studio .Net and Python 2.2.2. The
following code demostrates the problem:
------------------Begin Code ---------------------------
C++ code:
#include <iostream>
#include <string>
class Entity
{
public:
Entity() {Class = "Entity"; }
Entity(const Entity& e) { this->Class = e.Class; }
std::string virtual GetClass(std::string PreFix) {
return Class + PreFix; }
public:
std::string Class;
};
class SimpleEntity : public Entity
{
public:
SimpleEntity() { this->Class = "SimpleEntity"; }
SimpleEntity(const SimpleEntity& se) { this-
>Class = se.Class; }
std::string virtual GetClass(std::string PreFix) {
return Class + PreFix; }
};
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/args.hpp>
#include <boost/python/class.hpp>
#include <boost/python/overloads.hpp>
#include <boost/python/call_method.hpp>
using namespace boost::python;
std::string Test(Entity* e, std::string PreFix) {
return e->GetClass(PreFix);
}
class EntityWrap : public Entity
{
public:
EntityWrap(PyObject* self_) : self(self_) {}
EntityWrap(PyObject* self_, const Entity& e) :
self(self_), Entity(e) {}
std::string GetClass(std::string PreFix) { return
call_method<std::string>(self, "GetClass", PreFix); }
std::string default_GetClass( Entity& e,
std::string PreFix) { return e.Entity::GetClass(PreFix); }
private:
PyObject* self;
};
class SimpleEntityWrap : public SimpleEntity
{
public:
SimpleEntityWrap(PyObject* self_) : self(self_)
{}
SimpleEntityWrap(PyObject* self_, const
SimpleEntity& se) : self(self_), SimpleEntity(se) {}
std::string GetClass(std::string PreFix) { return
call_method<std::string>(self, "GetClass", PreFix); }
std::string default_GetClass( SimpleEntity& se,
std::string PreFix) { return se.SimpleEntity::GetClass
(PreFix); }
private:
PyObject* self;
};
BOOST_PYTHON_MODULE(hello)
{
class_<Entity, EntityWrap>("Entity")
.def(init<const Entity&>())
.def("GetClass",
&EntityWrap::default_GetClass)
.def_readwrite("Class",
&Entity::Class);
;
class_<SimpleEntity, SimpleEntityWrap,
bases<Entity> >("SimpleEntity")
.def(init<const SimpleEntity&>())
.def("GetClass",
&SimpleEntityWrap::default_GetClass)
;
def("Test", Test);
}
Python Code:
Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit
(Intel)] on win32
Type "copyright", "credits" or "license" for more information.
IDLE 0.8 -- press F1 for help
>>> from hello import *
>>>
class DerivedEntity(SimpleEntity):
def __init__(self):
SimpleEntity.Class = "DerivedEntity"
def GetClass(self,x):
return self.Class + x
>>> e = Entity()
>>> Test(e, " a test")
Traceback (most recent call last):
File "<pyshell#4>", line 1, in ?
Test(e, " a test")
TypeError: bad argument type for built-in operation
>>> s = SimpleEntity()
>>> Test(s, " a test")
Traceback (most recent call last):
File "<pyshell#6>", line 1, in ?
Test(s, " a test")
TypeError: bad argument type for built-in operation
>>> d = DerivedEntity()
>>> Test(d, " a test")
Traceback (most recent call last):
File "<pyshell#8>", line 1, in ?
Test(d, " a test")
TypeError: bad argument type for built-in operation
>>> e.Class
'Entity'
>>> e.GetClass(" a test")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in ?
e.GetClass(" a test")
TypeError: bad argument type for built-in operation
>>> s.Class
'DerivedEntity'
>>> s.GetClass("a test")
Traceback (most recent call last):
File "<pyshell#12>", line 1, in ?
s.GetClass("a test")
TypeError: bad argument type for built-in operation
>>> d.Class
'DerivedEntity'
>>> d.GetClass(" a test")
'DerivedEntity a test'
>>>
------------------End Code ---------------------------
Am I missing something? Any help would be appreciated.
Thanks, Vince
Change History (4)
comment:1 by , 20 years ago
comment:2 by , 20 years ago
Logged In: NO
Thanks for the fix Joel, everything works as expected now. I
really appreciate your prompt response. One last thing, I am
assuming that this solution is only applicable to the version of
boost currently in cvs? When I tried the same fix with version
1.29 it generates a compile error.
Much Thanks,
Vince
The above mentioned error in case you weren't aware.
C:\Documents and Settings\thomasinov\Desktop\boost_1_29_0
\boost\python\detail\de
f_helper.hpp(131) : error C2440: 'return' : cannot convert
from 'std::basic_stri
ng<_Elem,_Traits,_Ax> ' to 'const char *'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
There is no context in which this conversion is possible
C:\Documents and
Settings\thomasinov\Desktop\boost_1_29_0\boost\python\d
etail\def_helper.hpp(130) : while compiling class-template
member function 'cons
t char *boost::python::detail::def_helper<T1,T2,T3>::doc(void)
const'
with
[
T1=std::basic_string<char,std::char_traits<char>,std::allocator<c
har
>> (__thiscall EntityWrap::* )(std::string),
T2=boost::python::detail::not_specified,
T3=boost::python::detail::not_specified
]
C:\Documents and
Settings\thomasinov\Desktop\boost_1_29_0\boost\python\c
lass.hpp(362) : see reference to class template
instantiation 'boost::python::de
tail::def_helper<T1,T2,T3>' being compiled
with
[
T1=std::basic_string<char,std::char_traits<char>,std::allocator<c
har
>> (__thiscall EntityWrap::* )(std::string),
T2=boost::python::detail::not_specified,
T3=boost::python::detail::not_specified
]
C:\Documents and
Settings\thomasinov\Desktop\boost_1_29_0\boost\python\c
lass.hpp(227) : see reference to function template
instantiation 'void boost::py
thon::class_<T,X1,X2,X3>::dispatch_def(const void *,const char
*,std::basic_stri
ng<_Elem,_Traits,_Ax> ,std::basic_string<_Elem,_Traits,_Ax>
& )' being compiled
with
[
T=Entity,
X1=EntityWrap,
X2=boost::python::detail::not_specified,
X3=boost::python::detail::not_specified,
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
hello.cpp(141) : see reference to function template
instantiation 'boost
::python::class_<T,X1,X2,X3>::self
&boost::python::class_<T,X1,X2,X3>::def(const
char
*,std::basic_string<_Elem,_Traits,_Ax> ,std::basic_string<_Elem,
_Traits,_A
x> & )' being compiled
with
[
T=Entity,
X1=EntityWrap,
X2=boost::python::detail::not_specified,
X3=boost::python::detail::not_specified,
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]
comment:3 by , 20 years ago
Logged In: YES user_id=237817 Hi Vince, Yes, the solution requires the latest CVS code which is almost Boost 1.30.0 in just a few more days. Pardon me for not mentioning that. However, there is actually a 1.29.0 solution. See http://article.gmane.org/gmane.comp.python.c++/1861 for details. Cheers, -- Joel de Guzman joel at boost-consulting.com http://www.boost-consulting.com http://spirit.sf.net
comment:4 by , 16 years ago
| Status: | assigned → closed |
|---|
Note:
See TracTickets
for help on using tickets.

Logged In: YES user_id=237817 Hi Vince, The tutorial has been updated. There's a specific page now that focuses on virtual functions with default implementation. You can read it here: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/boost/boost/libs/python/doc/tutorial/doc/virtual_functions_with_default_implementations.html Attached is the corrected code. Most notably: std::string default_GetClass(std::string PreFix) { return Entity::GetClass(PreFix); } ... If you have to pass an object as the first argument, it has to be a static function. A non-static function will do. std::string default_GetClass(std::string PreFix) { return SimpleEntity::GetClass(PreFix); } ...Ditto. .def("GetClass", &Entity::GetClass, &EntityWrap::default_GetClass) ...See the tutorial link that I gave above. .def("GetClass", &SimpleEntity::GetClass, &SimpleEntityWrap::default_GetClass) ... Ditto Finally... >>> class DerivedEntity(SimpleEntity): ... def __init__(self): ... SimpleEntity.Class = "DerivedEntity" ... def GetClass(self,x): ... return self.Class + x looks suspicious. Doesn't it need to __init__ the base class? See the attached corrections. Regards, -- Joel de Guzman joel at boost-consulting.com http://www.boost-consulting.com http://spirit.sf.net