dynamic_cast is ugly!

J

Juha Nieminen

Daniel said:
Like what?

Like for example saving the settings of those objects to a file. (The
order in which they are saved into the file determines the order in
which they are loaded, which then restores the original order.)

And no, it may not be possible to simply have a "virtual void
saveSettings()" function in the base class.
 
J

Jerry Coffin

Like for example saving the settings of those objects to a file. (The
order in which they are saved into the file determines the order in
which they are loaded, which then restores the original order.)

And no, it may not be possible to simply have a "virtual void
saveSettings()" function in the base class.

If you could tell us more about _why_ it's not possible, that would
likely provide a lot more chance of somebody coming up with a real
solution for the problem. Right now, you simply haven't told us enough
for anybody to make an intelligent suggestion for how you should
proceed.
 
J

Juha Nieminen

Jerry said:
If you could tell us more about _why_ it's not possible, that would
likely provide a lot more chance of somebody coming up with a real
solution for the problem. Right now, you simply haven't told us enough
for anybody to make an intelligent suggestion for how you should
proceed.

Since this is related to my work, and my contract agreement is
extremely restrictive about what I can divulge about my job, I'm not
sure how much I can describe what I'm doing in detail. (It may be ok to
give more details, but better safe than sorry, I suppose.)
 
D

Daniel T.

Juha Nieminen said:
Jerry Coffin wrote:

Since this is related to my work, and my contract agreement is
extremely restrictive about what I can divulge about my job, I'm not
sure how much I can describe what I'm doing in detail. (It may be ok to
give more details, but better safe than sorry, I suppose.)

So what we are left with is you demanding concrete code for a very
nebulous problem. A problem which you have basically defined as, "what
if I need to use dynamic_cast and there is no other way to do it?"

I've answered that question more than once.
 
J

James Kanze

That may be the practice in poor designs, but it is not the
general case.

So explain the alternatives, and show how they're better. For
the moment, all you've said is "bad design", with no explination
as to why, or what would be better. Sort of like a child at a
playground.
 
D

Daniel T.

Matthias Buelow said:
I'm not sure I understand what you mean.

When looking at a bunch of code, one of the questions I ask myself is,
"what types (classes) can be used in this context?" The answer to that
is in the code with static typed languages, but not dynamic types.
 
D

Daniel T.

James Kanze said:
So explain the alternatives, and show how they're better. For
the moment, all you've said is "bad design", with no explination
as to why, or what would be better. Sort of like a child at a
playground.

Alternatives have been discussed throughout this thread. As for a
specific solution when no specific problem has been presented... I can't
do that.

The entire discussion with you has been me saying "try not to do that
(but sometimes you have to)", and you saying "sometimes you have do it
(but try not to.)" Maybe we aren't really on different sides of the
fence at all...
 
D

Daniel T.

James Kanze said:
So explain the alternatives, and show how they're better. For
the moment, all you've said is "bad design", with no explination
as to why, or what would be better. Sort of like a child at a
playground.

A related issue came up at work today...

Our framework has a class "Graphic", we have several classes derived
from it including "Image" and "Animation".

Graphics have rotate functionality, but they rotate about their center,
and what I needed was to be able to rotate the graphic about any
arbitrary point along the vertical center of the graphic. This meant
doing some math to change the x, y of the graphic as I was rotating it.

In addition, Graphics have a "bool hit( int x, int y ) const" function.
If the 'x' and 'y' are in the hit area of the graphic, then it returns
true. This function also needs to be modified so that it returns true if
a particular region of the graphic was hit based on the current rotation.

(To help picture the situation, imagine a picture of a crank. Normally,
for such an image, the fulcrum would be at the center of the crank, and
the hit region would be anywhere on the image. What I needed was for the
fulcrum to be at one end of the image, and the hit region to be at the
other.)

So, in my estimation, I need a decorator that changes what the rotate
and hit functions do.

class RotateableGraphic : public Graphic {
Graphic* graphic;
// other data to keep track of the sweep radius.
public:
RotateableGraphic( Graphic* g ): graphic( g ) { }

void rotate( int degrees ) {
// do math that rotates 'graphic' and changes its 'x' and 'y'
}

bool hit( int x, int y ) const {
// do the math to figure out if 'x' and 'y' are in the hit region
}
};

Part of the problem is that I also want to be able to call the
additional functions in Image and Animation even after adding it to the
RotateableGraphic.

It seems that some here would argue that the best thing to do would be
to provide a "getGraphic" function and then dynamic_cast it in order to
access that extra functionality. What would you do?
 
O

Owen Jacobson

  Like for example saving the settings of those objects to a file. (The
order in which they are saved into the file determines the order in
which they are loaded, which then restores the original order.)

  And no, it may not be possible to simply have a "virtual void
saveSettings()" function in the base class.

I've just gone back and re-read most of this thread to ensure that the
crucial points are clear in my mind. However, it's entirely possible
I've missed something.

It seems to me that you've elevated a property of shapes - "being a
square" - from the status of a property to the status of a type. C+
+'s support for predicate classes, a language feature that would make
this kind of specialization natural, is practically nonexistant, so
this may not have been a sensible way to model the problem domain.

That is: I would not have made squares into a class of their own, but
rather expressed them via a predicate function that can be applied to
shapes. By not elevating the predicate to the class hierarchy,
querying and selection against the predicate is much more natural.
You could, for example, have

vector<Shape *> squares = filter (shapes.begin (),
shapes.end (),
&is_square);

for some reasonable definition of the filter function.

In fact, this lends itself to compositional filters - you could write
is_square (Shape*) in terms of other queries against the number of
sides the shape has, how long each side is, and what the angle at each
vertex is, or any other combination of properties that defines a
square.

The tradeoff here is that the Shape class is reduced to holding
properties and completely generic behaviour - most of the behaviour
that would be specific to some types of shapes would end up being
implemented in helpers that accept Shape* (which would in turn have to
protect themselves from being passed non-square Shape*s).

I think this line of reasoning applies to the UML/UML_Interface/
UML_Class variation of this design point as well: "being an interface"
is not a natural fit for a C++ class distinction, but rather a
property of the underlying UML object.

-o
 
M

Michael DOUBEZ

Owen Jacobson a écrit :
I've just gone back and re-read most of this thread to ensure that the
crucial points are clear in my mind. However, it's entirely possible
I've missed something.

It seems to me that you've elevated a property of shapes - "being a
square" - from the status of a property to the status of a type. C+
+'s support for predicate classes, a language feature that would make
this kind of specialization natural, is practically nonexistant, so
this may not have been a sensible way to model the problem domain.

That is: I would not have made squares into a class of their own, but
rather expressed them via a predicate function that can be applied to
shapes. By not elevating the predicate to the class hierarchy,
querying and selection against the predicate is much more natural.
You could, for example, have

vector<Shape *> squares = filter (shapes.begin (),
shapes.end (),
&is_square);

for some reasonable definition of the filter function.

In fact, this lends itself to compositional filters - you could write
is_square (Shape*) in terms of other queries against the number of
sides the shape has, how long each side is, and what the angle at each
vertex is, or any other combination of properties that defines a
square.

The tradeoff here is that the Shape class is reduced to holding
properties and completely generic behaviour - most of the behaviour
that would be specific to some types of shapes would end up being
implemented in helpers that accept Shape* (which would in turn have to
protect themselves from being passed non-square Shape*s).

The only gain is that you don't apply a dynamic_cast<> on all elements
of the collection. This is a gain somewhat depending on the complexity
of the predicate but it doesn't remove the need for dynamic_cast<>.

The subject here was "How strong an indicator of bad design is
dynamic_cast<>() ?".

The answer I think is there are cases where you can find alternatives to
I think this line of reasoning applies to the UML/UML_Interface/
UML_Class variation of this design point as well: "being an interface"
is not a natural fit for a C++ class distinction, but rather a
property of the underlying UML object.

I don't understand here. There are two main ways to make it an interface
in c++:
- duck typing
- strong typing
"being an interface" is a natural fit I would say.

What is missing at the language level is the messaging system such as in
smalltalk (that you retrieve in dynamic typing language like python or
ruby). That can be emulated in C++ but it is heavier/uglier to
manipulate (I don't want to make this thread bigger by a static/dynamic
typing holy war so let it lie :) ).

Michael
 
J

Juha Nieminen

Michael said:
What is missing at the language level is the messaging system such as in
smalltalk (that you retrieve in dynamic typing language like python or
ruby). That can be emulated in C++ but it is heavier/uglier to
manipulate (I don't want to make this thread bigger by a static/dynamic
typing holy war so let it lie :) ).

Maybe what C++ needs is a kind of "type conditionals" (I don't know
what kind of paradigm this would fall into). Something along the lines of:

void foo(Shape* ptr)
{
switch(the_real_type_of(ptr))
{
case <Square*>(sPtr):
// Do something with sPtr
break;

case <Circle*>(cPtr):
// Do something with cPtr
break;
}
}

The advantage of this is that the compiler could generate code which
directly casts the pointer to the actual type it's pointing to, thus
saving the overhead and ugliness of repeated dynamic_casts, which may
fail. (After all, it feels useless to have to try different
dynamic_casts until you find the correct type.)

It would also avoid the overhead related to a true
messaging/delegation system.
 
M

Michael DOUBEZ

Juha Nieminen a écrit :
Maybe what C++ needs is a kind of "type conditionals" (I don't know
what kind of paradigm this would fall into). Something along the lines of:

void foo(Shape* ptr)
{
switch(the_real_type_of(ptr))
{
case <Square*>(sPtr):
// Do something with sPtr
break;

case <Circle*>(cPtr):
// Do something with cPtr
break;
}
}

The advantage of this is that the compiler could generate code which
directly casts the pointer to the actual type it's pointing to, thus
saving the overhead and ugliness of repeated dynamic_casts, which may
fail. (After all, it feels useless to have to try different
dynamic_casts until you find the correct type.)

In fact, it would be the same as a dynamic cast. The compiler would have
to perform a search, at runtime, in the inheritance tree of the
underlying object in order to find a match.

The only advantage of such a construct would be compared to

if(dynamic_cast<Square*>(sPtr))
{

}
else if(dynamic_cast<Circle*>(sPtr))
{

}
else
{

}

And that kind of construct is truly ugly from the design point of view.
Foo should go in the base class or if you want to make it
method-extensible, you should go to the overhead of a visitor pattern or
another construct.

Michael
 
D

Dmitry A. Kazakov

Maybe what C++ needs is a kind of "type conditionals" (I don't know
what kind of paradigm this would fall into).

It is manual dispatch (implemented by comparing types tags).
Something along the lines of:

void foo(Shape* ptr)
{
switch(the_real_type_of(ptr))
{
case <Square*>(sPtr):
// Do something with sPtr
break;

case <Circle*>(cPtr):
// Do something with cPtr
break;
}
}

In order to do this in a sane way you have first to separate "real"
(=specific) and "unreal" (=class-wide) types of objects. Otherwise the
(After all, it feels useless to have to try different
dynamic_casts until you find the correct type.)

It is same as with catching exceptions. Consider:

switch (*Ptr)
{
case (Square& Obj) { ... // deal with Obj }
case (Rectangle& Obj) { ... }

(I have changed the syntax to make it more obvious). Considering Square
derived from Rectangle, which alternative to select? When Square& and
Rectangle& are treated class-wide, then Square& is a part of Rectangle& (a
subclass). When Square& and Rectangle& are considered specific types, then
they are distinct.
It would also avoid the overhead related to a true
messaging/delegation system.

Better than manual dispatch are models where all arguments of a subprogram
are dispatching (virtual), including the result. In C++ only the first,
hidden argument is (when the subprogram is declared virtual).
 
A

Andy Champ

Owen Jacobson wrote:
That is: I would not have made squares into a class of their own, but
rather expressed them via a predicate function that can be applied to
shapes. By not elevating the predicate to the class hierarchy,
querying and selection against the predicate is much more natural.
You could, for example, have

Owen,
I don't see what that gains you over dynamic_cast, and I can see it
could give problems.

Under the hood, I expect dynamic_cast<Square*>(someShapePtr) does
something like:

if (&(someShapePtr->vtbl) == &vbtl_Square)
{
return someShapePtr;
}
else
{
return 0;
}

This isn't a complicated bit of code.

Your function would have to be declared on Shape - and a similar
function for every derived class - and implemented to return false. Or
if it isn't a member, you have to implement a static function that takes
a pointer and somehow without dynamic_cast discovers if it's a Shape*.

This is a lot of (simple) code, if you have lots of classes, and because
it is so simple you won't concentrate when duplicating it for a new
class - and so you'll have two classes with the same "type".

What *would* be useful - and I've thought of doing it in our project -
is a virtual function on each class that returns an ID. You could then
switch on the ID. But once again, it's error prone, and has been
pointed out, what is the position for a multi-level inheritance
hierarchy - is a square a rectangle? A Rhombus? A Parallelogram? A
Quadrilateral? A Polygon? Or just a square?

Andy
 
J

Juha Nieminen

Michael said:
In fact, it would be the same as a dynamic cast. The compiler would have
to perform a search, at runtime, in the inheritance tree of the
underlying object in order to find a match.

The point is that the compiler has to make it only *once*. When it has
found the correct type, it can directly jump to the proper "case" block.
This would not only be more efficient (because there's no "try dynamic
cast again and again against different types until you find the correct
one), the code becomes cleaner (basically the only dynamic cast is done
behind the scenes, and failure simply means that the 'default' block is
executed, or nothing at all if there's no such block).
 
L

lilburne

Daniel said:
So, in my estimation, I need a decorator that changes what the rotate
and hit functions do.

class RotateableGraphic : public Graphic {
Graphic* graphic;
// other data to keep track of the sweep radius.
public:
RotateableGraphic( Graphic* g ): graphic( g ) { }

void rotate( int degrees ) {
// do math that rotates 'graphic' and changes its 'x' and 'y'
}

bool hit( int x, int y ) const {
// do the math to figure out if 'x' and 'y' are in the hit region
}
};

Part of the problem is that I also want to be able to call the
additional functions in Image and Animation even after adding it to the
RotateableGraphic.

It seems that some here would argue that the best thing to do would be
to provide a "getGraphic" function and then dynamic_cast it in order to
access that extra functionality. What would you do?

Personally I'd use the cast, but I'd like to know how you get around not
using it.
 
D

Daniel T.

lilburne said:
Daniel T. wrote:

Personally I'd use the cast, but I'd like to know how you get around not
using it.

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.

Next solution... Make RotateableGraphic a template:

template < typename T >
class RotateableGraphic : public T
{
public:
// as above except 'g' is absent.
};

With this solution, RotateableGraphic can inherit from any type derived
from graphic and doesn't need to hold a pointer to a Graphic, since it
is the Graphic.

In the first case, if some other object wants to manipulate the graphic
as the derived type, then the creator of the object needs to pass a
reference to the object inside the RotateableGraphic, instead of the
RotateableGraphic object. This makes sense because the first object
created it, so knows its type, and the second object wants to use that
particular type so everything is obvious.

In the second case, there is no object inside the RotateableGraphic, but
it can be used as the appropriate type by simply *up-casting* one level,
(an operation that is guaranteed to succeed.)

In neither case would the RotateableGraphic class even have a
"getGraphic" member, so there is no question about pulling it out and
wondering what sub-type it may be.
 
K

kwikius

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.

Next solution... Make RotateableGraphic a template:

   template < typename T >
class RotateableGraphic : public T
{
public:
   // as above except 'g' is absent.

};

With this solution, RotateableGraphic can inherit from any type derived
from graphic and doesn't need to hold a pointer to a Graphic, since it
is the Graphic.

In the first case, if some other object wants to manipulate the graphic
as the derived type, then the creator of the object needs to pass a
reference to the object inside the RotateableGraphic, instead of the
RotateableGraphic object. This makes sense because the first object
created it, so knows its type, and the second object wants to use that
particular type so everything is obvious.

In the second case, there is no object inside the RotateableGraphic, but
it can be used as the appropriate type by simply *up-casting* one level,
(an operation that is guaranteed to succeed.)

In neither case would the RotateableGraphic class even have a
"getGraphic" member, so there is no question about pulling it out and
wondering what sub-type it may be.

The functionality in the first option seems somewhat fragile
because validity of the proxy RotatableViewOfObject depends on the
validity of the core 'graphic' object.

There seems to be no functionality provided to set the centre of
rotation or rotation angle angle as a graphic, this being additional
functionality, so whatever needs to manipulate a graphic as a
RotateableGraphic needs to ascertain it Is, the simplest solution for
that being AFAICS...dynamic_cast.

The cleverness or otherwise of the owner is irrelevant AFAICS.

regards
Andy Little
 
R

Richard Herring

In message
So explain the alternatives, and show how they're better. For
the moment, all you've said is "bad design", with no explination
as to why, or what would be better. Sort of like a child at a
playground.

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

;-/
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top