From: Marcelo M. <mm...@ac...> - 2006-02-12 21:24:54
|
ok, then to the last implementation, add the %newpointer_flags option, ie: %define %_factory_dispatch(Type){ Type *type = dynamic_cast<Type *>($1); if (type) return SWIG_NewPointerObj(%as_voidptr(type),$descriptor(Type *), $owner | %newpointer_flags); }%enddef %define %factory_method(Method,Base,Types...) %typemap(out,noblock=1) Base *Method { %formacro(%_factory_dispatch, Types) return SWIG_NewPointerObj(%as_voidptr($1),$descriptor, $owner | %newpointer_flags); }%enddef that of course, require all the objects use the track feature in a consistent way. Marcelo Charlie Savage wrote: > Okay, I'll give this a try. Yesterday evening I implemented the way > you suggested, and ran into an interesting issue. It conflicts with > Ruby object tracking. I saw this because the library uses > std::vectors of pointers to Geometry objects and children. > > The way the object tracking works is take the C++ pointer and look up > the Ruby object. Thus, the static method to do the downcast will run, > but then ConvertPtr will check the list of previously returned Ruby > objects and give you back the old one since the C++ object (pointer) > is of course the same. Aack! > > I think the fix is check the type of the returned Ruby object - if it > is different then create a new Ruby object, and associate the > ownership of the C++ with that new object. You of course need to keep > the old object around but remove its ownership of the C++ object. > That's not perfect because you now have 2 Ruby objects pointing to the > same C++ object (which is how the Ruby bindings works without object > tracking), but I don't see a way around that. > > So I'll update the object tracking to do this...just bummed that 1.28 > got released yesterday because its a just few minute fix (hopefully!). > > Charlie > > Marcelo Matus wrote: > >> Sorry again, here, simpler version, we don't need to add the >> dynamic_cast operation to derived types. >> >> Marcelo >> >> >> Charlie Savage wrote: >> >>> Thanks Marcelo, >>> >>> Very helpful. >>> Makes me wonder if there could be a more elegant way? Maybe a >>> template method on the Geometry class, so at least the downcast >>> method only has to be written once? >>> >>> Are there any plans to have SWIG generate this sort of code - at >>> least the downcast method/s ? >>> >>> Thanks, >>> >>> Charlie >>> >>> >>> >>> Marcelo Matus wrote: >>> >>>> you need to add the dynamic cast operations for all the Geometry >>>> object >>>> >>>> %extend Circle { >>>> static Circle *dcast(Geometry *g) { return dynamic_cast<Circle >>>> *>(g); } >>>> } >>>> >>>> %extend Point { >>>> static Point *dcast(Geometry *g) { return dynamic_cast<Point >>>> *>(g); } >>>> } >>>> >>>> .... >>>> >>>> then use the infamous 'switch' operation, but implemented in Ruby >>>> (here in pseudo C/Python): >>>> >>>> def unpackGeometry(geom_string): >>>> geom = GeomFactory.new.parseGeometry(geom_string) >>>> circle = GeomFactory.Circle.dcast(geom) >>>> if (circle != Qnil) return circle >>>> point = GeomFactory.Point.dcast(geom) >>>> if (point != Qnil) return point >>>> .... >>>> return Qnil >>>> >>>> >>>> and use it as >>>> >>>> obj = unpackGeometry(geom_string) >>>> >>>> then 'obj' will be what you expect, ie, a circle, or a point, etc. >>>> >>>> And of course, that is assuming Geometry has a virtual >>>> member/descructor. >>>> >>>> class Geometry { >>>> public: >>>> virtual ~Geometry() {} >>>> } >>>> >>>> >>>> Marcelo >>>> >>>> >>>> Charlie Savage wrote: >>>> >>>>> Hi everyone, >>>>> >>>>> Was wondering what the best way to handle this issue with C++ >>>>> inheritance (seem like an obvious question, but didn't dig >>>>> anything up with Google or the mailing list): >>>>> >>>>> class GeomFactory { >>>>> Geometry* parseGeometry(char* geom_serialized_to_string) {} >>>>> } >>>>> >>>>> class Geometry { >>>>> Geometry() {} >>>>> } >>>>> >>>>> class Point: public Geometry { >>>>> Point() {} >>>>> } >>>>> >>>>> class Line: public Geometry { >>>>> Line() {} >>>>> } >>>>> >>>>> Etc...including polygon, multipoint, multipolygon, geometry >>>>> collection, etc. >>>>> >>>>> So from Ruby: >>>>> >>>>> geom_string = '<serialized form of geometry>' >>>>> geom = GeomFactory.new.parseGeometry(geom_string) >>>>> >>>>> The class of geom will always be geom, not point, not line, not >>>>> polygon. Of course, the underlying C++ object is really a point, >>>>> line, etc. so the wrapper Ruby object is incorrect. >>>>> How do I get the correct Ruby wrapper object - i.e., a Ruby point >>>>> for a C++ point, a Ruby line for a C++ line, etc. >>>>> >>>>> Charlie >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> Question about C++ inheritance (I'm running into an issue with C++ >>>>> inheritance and haven't managed to find anWas wondering if >>>>> any...@li... >>>> >>>> >>>> >>>> >>>> >>>> >> >>------------------------------------------------------------------------ >> >>/* >> Implement a more natural wrap for factory methods, for example, if >> you have: >> >> %inline >> { >> struct Geometry { >> enum GeomType{ >> POINT, >> CIRCLE >> }; >> >> virtual ~Geometry() {} >> virtual int draw() = 0; >> static Geometry *create(GeomType i); >> }; >> >> struct Point : Geometry { >> int draw() { return 1; } >> double width() { return 0.5; } >> }; >> >> struct Circle : Geometry { >> int draw() { return 1; } >> double radius() { return 1.5; } >> }; >> } >> >> %{ >> Geometry *Geometry::create(GeomType i) { >> switch (i) { >> case POINT: return new Point(); >> case CIRCLE: return new Circle(); >> default: return 0; >> } >> } >> %} >> >> You can use the %factory_method as follows: >> >> %newobject Geometry::create; >> %factory_method(Geometry::create, Geometry, Point, Circle); >> >> and Geometry::create will return a 'Point' or 'Circle' instance >> instead of the plain 'Geometry' type. >> >> circle = Geometry.create(Geometry.CIRCLE) >> r = circle.radius() >> >>*/ >>%define %_factory_dispatch(Type){ >> Type *type = dynamic_cast<Type *>($1); >> if (type) return SWIG_NewPointerObj(%as_voidptr(type),$descriptor(Type *), $owner); >>}%enddef >> >>%define %factory_method(Method,Base,Types...) >>%typemap(out,noblock=1) Base *Method { >> %formacro(%_factory_dispatch, Types) >> return SWIG_NewPointerObj(%as_voidptr($1),$descriptor, $owner); >>}%enddef >> >> |