dynamic_cast is ugly!

J

James Kanze

[...]
I understand the correct unanswerable put-down in these
circumstances is "won't pass code review in any place I've
ever worked in"

That can be a problem. If the local coding guidelines forbid
dynamic_cast, then you have a problem. (In practice, I've found
the reverse to be true: before dynamic_cast was part of the
language, we developed techniques to emulate it. Because
although it can easily be abused, it's a necessary part of OO
design.)
 
L

lilburne

Daniel said:
First solution... Note that the code I wrote above has no destructor, so
what happens to the graphic passed in when the RotaeableGraphic object
is destroyed? That is a clue. The object that passes in the Graphic
still has it and can call any functions it wants on it. So, for example,
an object can create an Image and pass it to a RotateableGraphic object,
then call the additional Image methods on it anytime he wants. In the
mean time, he can pass the RotateableGraphic to any generic Graphic
containers and they will ultimately modify the state of the Image
contained.

The problem is that in the cases I have its the reading code that has
created the objects, and built up topologies of different types of
surfaces, stitched together by shared edge curves and faces. So the
application sees

Topology->Face[]->Surface->Edges[]->Curve

But ignore most of that and just consider the Curve types

Curve -
| TransformedCurve
| Bezier
| Nurb
| Arc
| Polyline
| CompositeCurve
| ProjectedCurve
| SurfaceCurve
| ReversedCurve

CompositeCurve(Curve[])
TransformedCurve(Curve, Xform)
ProjectedCurve(Curve, Plane)
SurfaceCurve(Surface)


Lets say I want to extract all the edge curves from a topology and
perform some analysis on them. Because certain types of geometric
analysis can be performed more quickly if one knows what the type is,
for example arc-line intersection, or arc-arc intersection, one also
wants to avoid wrapping if possible.

So whilst a method that involved transforming all the input may just
wrap the input curves in a TransformCurve as that wouldn't require a
deep copy of the curves (you wouldn't simple physically transform the
curves themselves because that would require transforming the topology).
it may well decide to retain any Arcs or Polylines in the input, so one
may well dynamically cast for those type, and deep copy and physically
transform just those types.

I was hoping your solution would help in situations like that, but
thanks anyway.
 
M

Michael DOUBEZ

lilburne a écrit :
Daniel said:
First solution... Note that the code I wrote above has no destructor,
so what happens to the graphic passed in when the RotaeableGraphic
object is destroyed? That is a clue. The object that passes in the
Graphic still has it and can call any functions it wants on it. So,
for example, an object can create an Image and pass it to a
RotateableGraphic object, then call the additional Image methods on it
anytime he wants. In the mean time, he can pass the RotateableGraphic
to any generic Graphic containers and they will ultimately modify the
state of the Image contained.

The problem is that in the cases I have its the reading code that has
created the objects, and built up topologies of different types of
surfaces, stitched together by shared edge curves and faces. So the
application sees

Topology->Face[]->Surface->Edges[]->Curve

But ignore most of that and just consider the Curve types

Curve -
| TransformedCurve
| Bezier
| Nurb
| Arc
| Polyline
| CompositeCurve
| ProjectedCurve
| SurfaceCurve
| ReversedCurve

CompositeCurve(Curve[])
TransformedCurve(Curve, Xform)
ProjectedCurve(Curve, Plane)
SurfaceCurve(Surface)


Lets say I want to extract all the edge curves from a topology and
perform some analysis on them. Because certain types of geometric
analysis can be performed more quickly if one knows what the type is,
for example arc-line intersection, or arc-arc intersection, one also
wants to avoid wrapping if possible.

So whilst a method that involved transforming all the input may just
wrap the input curves in a TransformCurve as that wouldn't require a
deep copy of the curves (you wouldn't simple physically transform the
curves themselves because that would require transforming the topology).
it may well decide to retain any Arcs or Polylines in the input, so one
may well dynamically cast for those type, and deep copy and physically
transform just those types.

I was hoping your solution would help in situations like that, but
thanks anyway.

Your problem is different: you have a limited number of class to
consider (there is only so much curve classes ...) but you might want to
extend the procedures applied to you topology (rendering,
searching,finding a path ...) .
This is typically the case where a visitor pattern is IMO a good option.

Michael
 
H

Hang Dog

Michael said:
lilburne a écrit :
The problem is that in the cases I have its the reading code that has
created the objects, and built up topologies of different types of
surfaces, stitched together by shared edge curves and faces. So the
application sees

Topology->Face[]->Surface->Edges[]->Curve

But ignore most of that and just consider the Curve types

Curve -
| TransformedCurve
| Bezier
| Nurb
| Arc
| Polyline
| CompositeCurve
| ProjectedCurve
| SurfaceCurve
| ReversedCurve

CompositeCurve(Curve[])
TransformedCurve(Curve, Xform)
ProjectedCurve(Curve, Plane)
SurfaceCurve(Surface)


Lets say I want to extract all the edge curves from a topology and
perform some analysis on them. Because certain types of geometric
analysis can be performed more quickly if one knows what the type is,
for example arc-line intersection, or arc-arc intersection, one also
wants to avoid wrapping if possible.

So whilst a method that involved transforming all the input may just
wrap the input curves in a TransformCurve as that wouldn't require a
deep copy of the curves (you wouldn't simple physically transform the
curves themselves because that would require transforming the
topology). it may well decide to retain any Arcs or Polylines in the
input, so one may well dynamically cast for those type, and deep copy
and physically transform just those types.

I was hoping your solution would help in situations like that, but
thanks anyway.

Your problem is different: you have a limited number of class to
consider (there is only so much curve classes ...)


There are 'only so much' in most other domains too.

but you might want to
extend the procedures applied to you topology (rendering,
searching,finding a path ...) .

One wouldn't want to pollute the geometry classes with graphical
knowledge, these underlaying classes describe the geometry
mathematically. But you've highlight another example of the problem: it
is far more efficient to render a trimmed plane or cylinder than it is
to render a swoopy surface. So the graphical rendering engine also
dynamically casts to optimize its handling of the simple cases.
> This is typically the case where a visitor pattern is IMO a good
> option.
>

For some methods each curve needs to be processed in strict order
regardless of its type. I can't for example drive a plotter to draw all
the lines, then all the arcs, then all the other bits. Well I could but
the users will get rather upset as the pen lifts off the paper and jumps
around not drawing anything.
 
M

Michael DOUBEZ

Hang Dog a écrit :
Michael said:
lilburne a écrit :
The problem is that in the cases I have its the reading code that has
created the objects, and built up topologies of different types of
surfaces, stitched together by shared edge curves and faces. So the
application sees

Topology->Face[]->Surface->Edges[]->Curve

But ignore most of that and just consider the Curve types

Curve -
| TransformedCurve
| Bezier
| Nurb
| Arc
| Polyline
| CompositeCurve
| ProjectedCurve
| SurfaceCurve
| ReversedCurve

CompositeCurve(Curve[])
TransformedCurve(Curve, Xform)
ProjectedCurve(Curve, Plane)
SurfaceCurve(Surface)


Lets say I want to extract all the edge curves from a topology and
perform some analysis on them. Because certain types of geometric
analysis can be performed more quickly if one knows what the type is,
for example arc-line intersection, or arc-arc intersection, one also
wants to avoid wrapping if possible.

So whilst a method that involved transforming all the input may just
wrap the input curves in a TransformCurve as that wouldn't require a
deep copy of the curves (you wouldn't simple physically transform the
curves themselves because that would require transforming the
topology). it may well decide to retain any Arcs or Polylines in the
input, so one may well dynamically cast for those type, and deep
copy and physically transform just those types.

I was hoping your solution would help in situations like that, but
thanks anyway.

Your problem is different: you have a limited number of class to
consider (there is only so much curve classes ...)


There are 'only so much' in most other domains too.

But in other domains, the set of method is limited and it is the
hierarchy that tends to evolve.
In your case, adding another kind of curve is less likely to happen than
adding another operation on your lattice.
One wouldn't want to pollute the geometry classes with graphical
knowledge, these underlaying classes describe the geometry
mathematically.

That is why the visitor patten fits quite well. Your classes can be
dedicated to describing your topology while you can extend the
application with new visitors.
But you've highlight another example of the problem: it
is far more efficient to render a trimmed plane or cylinder than it is
to render a swoopy surface. So the graphical rendering engine also
dynamically casts to optimize its handling of the simple cases.

The visitor can choose the hierarchy depth at which it will work, there
are usually default visitor for unhandled cases: no-op, delegation to
inherited class' visitation function, assert ...
For some methods each curve needs to be processed in strict order
regardless of its type. I can't for example drive a plotter to draw all
the lines, then all the arcs, then all the other bits. Well I could but
the users will get rather upset as the pen lifts off the paper and jumps
around not drawing anything.

Yes but the order of visitation is another concern. Usually, one pass a
visitor and a visitation strategy in order to determine how the tree is
spanned.

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top