The merits of dynamic_cast<>()

N

Noah Roberts

Joshua said:
Sam, your suggestion is similar to several common anti-patterns, such
as the god object
http://www.c2.com/cgi/wiki?GodObject

Exactly. This inevitably leads to serious maintenance issues later on
and can introduce numerous hard to debug errors even in green pasture
code. Don't do it!
By having each virtual function throw an "unsupported exception" by
default, and derived types implement some of them, you do not
establish actual "subtypes", only "derived types". The derived types
do not obey LSP (or they do trivially because your base class has no
contract, and thus is unusable). It is generally recognized that
pretending you have LSP subtypes when you do not is a source of bad
code.

The problem is that too few people recognize the subclass relationship
in this manner. They view inheritance as an opportunity for reuse or
worse: the best or ONLY opportunity for reuse. I was actually lectured
by a supervisor one time that the entire purpose of the inheritance
relationship was for reuse when I suggested separating some
responsibilities. This kind of reasoning about inheritance leads
directly to the kind of design being proposed here. The supervisor of
whom I speak made designs with numerous God objects and a whole slew of
subclasses that needed to implement a bunch of functions that had
nothing to do with them....just to be in a list structure.
 
A

Andreas Dehmel

[snipped original post about usage of dynamic_casts]


Andreas said:
Try doing that with e.g. a drawing program where all sorts of different
objects have to be processed in arbitrarily interleaved order

I don't quire get what you mean by "arbitrarily interleaved order"?
[OT: Könnten Sie mir das bitte mal auf Deutsch erklären?]

Since this is an english newgroup: no, but I'll try to elaborate. In
something like a drawing program you have objects and their position
on the drawing stack. Type has nothing to do with position, hence any
operation which has to honour stack position (like drawing or finding
the topmost object via graphical positions) has to process N lists
interleaved rather than just one (in which you'd get the stack position
entirely for free). Stack positions have to be unique, so you'll have to
guarantee that over N lists. For many other operations, all types will
behave the same, so you'll need N identical implementations (which may
be addressed via templates, but that still results in N implementations
on object code level). Keeping one object in multiple lists depending on
the view is also a bad idea because redundancy always implies a high risk
of inconsistency. If new types appear, you'll need new lists and all code
processing the objects will have to take the new lists into account;
besides, what makes you think you'd actually know all types at the time
of writing, e.g. in a library context? Your approach simply does not scale
at all. And while it may seem simple enough to initially build such a
system, keeping it consistent over editing (run-time), extensions and
maintenance (source code) is another thing entirely (and good luck trying
to keep it consistent whilst recovering from an out-of-memory situation).
It _can_ be done, but the result will definitely not be more readable or
maintainable than one list and the occasional dynamic cast; rather the
complete opposite.

I don't understand why the problem space, drawing programs, should be
prone to dynamic_casts. Could you please elaborate what technical/
maintainance reason there is why we have to use dynamic_casts in
drawing programs? I'd really be interested.

The maintenance reasons against multiple lists for something like this I
explained above. With a single list, the need for dynamic casts arises
when you actually need to address properties of specific objects. Such
as the radius of a circle or the control points of a bezier curve,
neither of which belong into the base interface because they're not
common properties of all shapes. It gets really great for something
like "Does A intersect B" (and I don't mean bounding boxes but the
real deal which needs to know the exact properties of both shapes,
e.g. circle and bezier curve). Trying to do this with N containers
and without dynamic casts would mean N^2 implementations of the entire
code sequence from retrieving the objects from their respective
containers based on some criteria (usually not type-related) to the
actual evaluation of the intersection function (N functions, actually,
one for each type). The only feasible way to do this would be heavily
templated code, which'll still create massively bloated object code.
Compared to all this, occasional dynamic casts are a ridiculously
small price to pay.

Another example would be GUI libraries. They all have different widget
types and sometimes need to address type-specific properties. I've
seen a few of them, but I've never come across one which keeps its
widgets in different lists by type. It'd be pretty much the worst
possible design in situations like these. It probably is for most
non-trivial problems, actually.

Agreed. To much dogmatism is bad. However, I can only imaging one
reason why dynamic_cast should be preferred over the multiple-
container solution: If your application contains a real _huge_ number
of very small objects, the cost of having to keep additional
containers for specific objects may consume too much memory. May this
be the reason you had originally in mind?

No. Why would keeping N objects in M containers need considerably more
memory than keeping them in one container? The space needed by the
objects is the same and your code will be an unmaintainable, bloated
corpse long before the memory overhead of M-1 containers becomes an issue.



Andreas
 
J

Joshua Maurice

The maintenance reasons against multiple lists for something like this I
explained above. With a single list, the need for dynamic casts arises
when you actually need to address properties of specific objects. Such
as the radius of a circle or the control points of a bezier curve,
neither of which belong into the base interface because they're not
common properties of all shapes. It gets really great for something
like "Does A intersect B" (and I don't mean bounding boxes but the
real deal which needs to know the exact properties of both shapes,
e.g. circle and bezier curve). Trying to do this with N containers
and without dynamic casts would mean N^2 implementations of the entire
code sequence from retrieving the objects from their respective
containers based on some criteria (usually not type-related) to the
actual evaluation of the intersection function (N functions, actually,
one for each type). The only feasible way to do this would be heavily
templated code, which'll still create massively bloated object code.
Compared to all this, occasional dynamic casts are a ridiculously
small price to pay.

Another example would be GUI libraries. They all have different widget
types and sometimes need to address type-specific properties. I've
seen a few of them, but I've never come across one which keeps its
widgets in different lists by type. It'd be pretty much the worst
possible design in situations like these. It probably is for most
non-trivial problems, actually.

Your example of object collision seems like double dispatch. You need
to invoke an algorithm which depends on the dynamic type of two
different objects. Offhand, I would guess that you do need explicit
casts somewhere to reasonably do this. (Or are there better ways to do
double dispatch?) However, I believe this is an outlier and not the
usual case.
No. Why would keeping N objects in M containers need considerably more
memory than keeping them in one container? The space needed by the
objects is the same and your code will be an unmaintainable, bloated
corpse long before the memory overhead of M-1 containers becomes an issue..

For very small objects, the size of the pointers in the containers may
be on the same order as the size of the objects themselves. Having
separate lists could noticeably increase memory usage.
 
T

Thomas J. Gritzan

Sam said:
Noah said:
Where? The solution you propose is worse. Where's the better one?

Really? Let's just review the alternatives:

On one hand, you are required to invoke dynamic_cast<> all over the
place. You are required to check the result of the dynamic_cast<>, every
time. If you end up with a null pointer, you must explicitly handle the
error condition, every time.

On the other hand, virtual methods are now invoked in the superclass,
instead. If the superclass is not an instance of an appropriate
subclass, the default implementation in the superclass ends up throwing
an exception. [...]

Well, then let the dynamic_casts throw an exception instead. No need to
check for NULL in this case.

Function that don't belong into the base class shouldn't be put there.
But it is a design trade-off, of course: dynamic_casts all over the
place or a bloated base class?
Maybe the base class should be split into smaller parts (classes) with
specific, single purpose interfaces. dynamic_cast would be a way to ask
if an object supports a specific interface.
 
J

Joshua Maurice

For very small objects, the size of the pointers in the containers may
be on the same order as the size of the objects themselves. Having
separate lists could noticeably increase memory usage.

Err, to be clear, if the lists are disjoint, then no additional
memory. However, if you keep an object in more than one list, then you
might use additional memory. The presumption was that an object would
have a pointer in several lists.
 
A

Alf P. Steinbach

* Leslaw Bieniasz:
I have a base class A, and a number of derived classes B, C, etc.
The problem is that although the classes have a lot of common
functionality (contained in A), there are also some specific
features (new methods) added to B, C, etc.
But, since there is a common functionality, it is convenient to
keep pointers to the various objects as pointers to A, in a common
container. This implies that whenever I need to access the common
functionality, I can use pointers to A, but if I need the specific
features, I have to cast from the pointer to A, to pointers to derived
classes. Is this OK,

The number of tails depends on the dog.

or there are ways to implement the same
thing without using dynamic_cast<>() ?

Depends. You should look up the visitor pattern. But as mentioned by James Kanze
else-thread, in some situations casting can be the most reasonable thing to do.

For the case of objects representing states I've found it useful, in the sense
of clarity, to use simple event handling where the event object performs a
dynamic cast of the target to the event object's handler interface, and if that
interface isn't present, calling a default handler on the object[1]. This avoids
a cluttered central "God object" interface and makes the intent more clear: any
object may simply ignore any event. But this is less than natural when the
actions can't be modeled as simple events (preferably without arguments).

If neither approach seems feasible then consider the knowledge distribution of
your design. The need for casting arises because the knowledge needed for some
action isn't present where the responsibility for carrying out the action has
been assigned. The trick is then to make the knowledge available where it's
needed, by moving or referencing the knowledge and/or the action responsibility.


Cheers & hth.,

- Alf

Notes:
[1] In C++, where generality is not cheap, I just use a simple two-level
hierarchy: completely generic handler or event-specific handler, templated. In
Java, with introspection, I once generalized this idea to general hierarchies of
handler interfaces. I can report that although it's theoretically a very nice
idea in practice it's just inefficiency and complexity for very little gain.
 
J

Joshua Maurice

Thomas said:
Sam said:
Noah Roberts writes:
Sam wrote:
You are redefining the OP's question. The OP wants to eliminate a
bunch of messy dynamic_cast<>s. That's all. The OP was not explicitly
interested in some theoretically pure solution, just a better way of
doing things. Well, here's a better way of doing things.
Where?  The solution you propose is worse.  Where's the better one?
Really? Let's just review the alternatives:
On one hand, you are required to invoke dynamic_cast<> all over the
place. You are required to check the result of the dynamic_cast<>, every
time. If you end up with a null pointer, you must explicitly handle the
error condition, every time.
On the other hand, virtual methods are now invoked in the superclass,
instead. If the superclass is not an instance of an appropriate
subclass, the default implementation in the superclass ends up throwing
an exception. [...]
Well, then let the dynamic_casts throw an exception instead. No need to
check for NULL in this case.

Okedokee. Let's propose that as a change to the C++ language, and wait for
it to be adopted. What a great idea.

Problem solved!
Function that don't belong into the base class shouldn't be put there.

Sure, that may be the case inside the ivory halls of academia, where
everyone strives for strict adherence to utopian design goals. But the real
world, well, that's not always that cut and try.
But it is a design trade-off, of course: dynamic_casts all over the
place or a bloated base class?
Maybe the base class should be split into smaller parts (classes) with
specific, single purpose interfaces. dynamic_cast would be a way to ask
if an object supports a specific interface.

Right. And we have to do it every time! And explicitly include the
alternative code paths dozens of times, one for each occurence of
dynamic_cast<>! Meticulous writing, testing, and debugging all of those
execution paths is just so much easier than just having one small exception
handler that covers all the bases!

Even if such a thing was not already supported (but it is), you could
do it yourself as a one liner.

Already supported example:
A* a;
B& b = dynamic_cast<B&>(*a);

If it wasn't supported, or if you would prefer a pointer to pointer
cast, one could do (disclaimer: entirely untested):

//don't use this directly
template <typename T, typename U>
T* throwing_dyn_cast_impl(T* , U* u)
{ T* tmp = dynamic_cast<T*>(u);
if (0 == tmp) throw 0; //replace with desired exception
return tmp;
}

//use this directly
template <typename T, typename U>
T throwing_dyn_cast(U u)
{ T foo = 0; //used for template type deduction
return throwing_dyn_cast_impl(foo, u);
}

//example usage:
struct A { virtual ~A() {} };
struct B : A {};
A* x = new A;
B* y = throwing_dyn_cast<B*>(x);

and just use throwing_dyn_cast everywhere in place of dynamic_cast for
pointer types. Your sarcastic tirade entirely lacks merit. If you want
an operation to throw when it currently returns an error code, it's
quite easy to define a wrapper helper function like above which has
the exact same semantics except it throws on an error. Factoring out
common code like this is a trivial, everyday part of programming.
 
J

James Kanze

Your example of object collision seems like double dispatch.

Not really. I think it probably is a case where most of the
interface should be in the base class, any code needing the
additional functionality keeps a more strictly typed pointer,
and no dynamic_cast is needed.
You need to invoke an algorithm which depends on the dynamic
type of two different objects. Offhand, I would guess that you
do need explicit casts somewhere to reasonably do this. (Or
are there better ways to do double dispatch?) However, I
believe this is an outlier and not the usual case.

The usual solution for double dispatch doesn't use dynamic_cast,
but it does involve knowing all of the derived interfaces
somewhere, typically in a visitor. An alternative might be to
use free functions, and some sort of map (indexed by a pair of
typeid).
 
J

James Kanze

The problem is that too few people recognize the subclass
relationship in this manner. They view inheritance as an
opportunity for reuse or worse: the best or ONLY opportunity
for reuse. I was actually lectured by a supervisor one time
that the entire purpose of the inheritance relationship was
for reuse when I suggested separating some responsibilities.

Perhaps he was coming from Smalltalk (and an IMHO out of date
point of view concerning inheritance). In C++, we usually
distinguish two types of inheritance, interface and
implementation, with private inheritance being used for the
latter, and a realization that containment is usually
preferrable to inheritance for implementation. In Smalltalk,
interfaces are only defined by documentation; there's no static
type checking what so ever. (And the dynamic typing is more or
less duck-typing, like that used in C++ templates.) The only use
of inheritance is implementation. And the realization that
containment is preferrable is rather recent, I think.
 
J

James Kanze

James,
Why not:
std::cout<< double(count) * 100 / max << '%' ;
and save some typing ?

Because the goal of the posting was to show a legitimate use of
casting (aka explicit type conversion), and I wanted to clearly
demonstrate the type of cast involved. In actual code, I
generally use a C style cast ("(double)( count )") in such
cases.
 
K

Krice

But doing so violates some kind of an utopian design goal,
apparently, so we're told it's no good because of that.

It's possible to live without good design and make
programs that use all kinds of hacks, but if you ever
programmed a large scale application you really wish you
had followed good design rules. I also believe that class
design itself is much harder than people often think, so
they make a lot of mistakes in that area of programming.
 
S

Stuart Redmann

[snipped previous discussion about dynamic_cast]

Andreas said:
In
something like a drawing program you have objects and their position
on the drawing stack. Type has nothing to do with position, hence any
operation which has to honour stack position (like drawing or finding
the topmost object via graphical positions) has to process N lists
interleaved rather than just one (in which you'd get the stack position
entirely for free). Stack positions have to be unique, so you'll have to
guarantee that over N lists.

Maybe I should elaborate my point of view a little bit: When I said
that I wanted to store the objects in multiple lists, I did not mean
that the original list should be discarded:

class CGeometricObject
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const = 0;
};

class CCircle
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const
{
// Draw a circle
}
private:
// Whatever is needed.
};

class CRectangle
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const
{
// Draw a circle
}
private:
// Whatever is needed.
};

class CDrawingApplication
{
private:
// The stack that contains all objects in the order
// in which they should appear on the screen from top
// to bottom.
std::list<CGeometricObject*> GeometricObjects;

// The list of geometric objects that must be handled in a
// special way by the application.
std::list<CCircle> Circles;
std::list<CRectangle> Rectangles;

public:
void AddCircle (const CCircle& Circle)
{
Circles.push_back (Circle);
GeometricObjects.push_back (&Circle);
}
void AddRectangle (const CRectangle& Rectangle)
{
Rectangles.push_back (Rectangle);
GeometricObjects.push_back (&Rectangle);
}

void Draw (/*SomeDeviceContextType dc*/)
{
for (std::list<CGeometricObject*>::iterator it =
GeometricObjects.begin (); it != GeometricObjects.end (); +
+it)
{
it->Draw ();
}
}
};
For many other operations, all types will
behave the same, so you'll need N identical implementations (which may
be addressed via templates, but that still results in N implementations
on object code level). Keeping one object in multiple lists depending on
the view is also a bad idea because redundancy always implies a high risk
of inconsistency. If new types appear, you'll need new lists and all code
processing the objects will have to take the new lists into account;

Nope. All code that uses only the base interface CGeometricObject can
stay as it is (see above example of CDrawingApplication::Draw).
However, if the application needs to do something special to a new
class (let's say CTriangle), the newly added method for triangle-
specific handling can simply just the newly added list of triangles.
besides, what makes you think you'd actually know all types at the time
of writing, e.g. in a library context?

Right. Now we are getting to some constraints that have not been
mentioned yet. Libraries that must facilitate for extensions may be a
reason why one should have to use dynamic_casts, although I am not
sure why the drawing program should be such a candidate. Consider
this: If the user wants to add a geometric object of unknown type, the
application can do nothing with it except things that are provided by
the base interface CGeometricObject. So there is no need to keep a
special list for the new type.

[snip]
It gets really great for something
like "Does A intersect B" (and I don't mean bounding boxes but the
real deal which needs to know the exact properties of both shapes,
e.g. circle and bezier curve). Trying to do this with N containers
and without dynamic casts would mean N^2 implementations of the entire
code sequence from retrieving the objects from their respective
containers based on some criteria (usually not type-related) to the
actual evaluation of the intersection function (N functions, actually,
one for each type).

I don't think that this is true. I would just add the following method
to the base interface:
bool Intersects (const CGeometricObject* Other) const = 0;
Now I can add a method to CPaintApplication that computes all
intersections:
std::list<std::pair<CGeometricObject*,CGeometricObject*> >
ComputeIntersections ()
{
std::list<std::pair<CGeometricObject*,CGeometricObject*> > RetVal;
for (std::list<CGeometricObject*>::iterator first =
GeometricObjects.begin ();
first != GeometricObjects.end (); ++first)
{
std::list<std::pair<CGeometricObject*,CGeometricObject*> > RetVal;
for (std::list<CGeometricObject*>::iterator first =
GeometricObjects.begin ();
first != GeometricObjects.end (); ++first)
{
std::list<CGeometricObject*>::iterator second = first;
++second;
for (; second != GeometricObjects.end (); ++second)
{
if ((*first)->Intersects (*second))
RetVal.push_back (
std::pair<CGeometricObject*,CGeometricObject*>
(*first, *second));
}
}
return RetVal;
}
}
No. Why would keeping N objects in M containers need considerably more
memory than keeping them in one container?

I would need additional space because I reference the same object from
two containers: One that is specific to the runtime type and one that
uses the base type of the object.

The whole code would look like this (including the Double Dispatch
meachanism, as Joshua proposed in his posting down this sub-thread):

#include <list>
#include <iostream>

class CCircle;
class CRectangle;

class CGeometricObject
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const = 0;
virtual bool Intersects (const CGeometricObject* Other) const = 0;
virtual bool _Intersects (const CCircle* OtherCircle) const = 0;
virtual bool _Intersects (const CRectangle* OtherRectangle) const =
0;
};

class CCircle : public CGeometricObject
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const
{
// Draw a circle
}
virtual bool Intersects (const CGeometricObject* Other) const
{
// Perform double Dispatch: Forward the call to the other object.
return Other->_Intersects (this);
}

// Those methods are necessary to provide for Double Dispatch.
virtual bool _Intersects (const CCircle* OtherCircle) const
{
std::cout << "Computing Intersection between two circles.";
return true;
}
virtual bool _Intersects (const CRectangle* OtherRectangle) const
{
std::cout << "Computing Intersection between circle and
rectangle.";
return true;
}

private:
// Whatever is needed.
};

class CRectangle : public CGeometricObject
{
public:
virtual void Draw (/*SomeDeviceContextType& dc*/) const
{
// Draw a circle
}

virtual bool Intersects (const CGeometricObject* Other) const
{
// Perform double Dispatch: Forward the call to the other object.
return Other->_Intersects (this);
}

virtual bool _Intersects (const CCircle* OtherCircle) const
{
std::cout << "Computing Intersection between circle and
rectangle.";
return true;
}
virtual bool _Intersects (const CRectangle* OtherRectangle) const
{
std::cout << "Computing Intersection between two rectangles.";
return true;
}

private:
// Whatever is needed.
};

class CDrawingApplication
{
private:
// The stack that contains all objects in the order
// in which they should appear on the screen from top
// to bottom.
std::list<CGeometricObject*> GeometricObjects;

// The list of geometric objects that must be handled in a
// special way by the application.
std::list<CCircle*> Circles;
std::list<CRectangle*> Rectangles;

public:
void AddCircle (CCircle* Circle)
{
Circles.push_back (Circle);
GeometricObjects.push_back (Circle);
}
void AddRectangle (CRectangle* Rectangle)
{
Rectangles.push_back (Rectangle);
GeometricObjects.push_back (Rectangle);
}

void Draw (/*SomeDeviceContextType dc*/)
{
for (std::list<CGeometricObject*>::iterator it =
GeometricObjects.begin (); it != GeometricObjects.end (); +
+it)
{
(*it)->Draw ();
}
}
std::list<std::pair<CGeometricObject*,CGeometricObject*> >
ComputeIntersections ()
{
std::list<std::pair<CGeometricObject*,CGeometricObject*> > RetVal;
for (std::list<CGeometricObject*>::iterator first =
GeometricObjects.begin ();
first != GeometricObjects.end (); ++first)
{
std::list<CGeometricObject*>::iterator second = first;
++second;
for (; second != GeometricObjects.end (); ++second)
{
if ((*first)->Intersects (*second))
RetVal.push_back
(std::pair<CGeometricObject*,CGeometricObject*> (*first, *second));
}
}
return RetVal;
}
};


int main()
{
CDrawingApplication app;
CCircle Circle;
CRectangle Rectangle;
app.AddCircle (&Circle);
app.AddRectangle (&Rectangle);
app.ComputeIntersections ();
return 0;
}

What do you think?

Stuart
 
N

Nick Keighley

Perhaps he was coming from Smalltalk (and an IMHO out of date
point of view concerning inheritance).  In C++, we usually
distinguish two types of inheritance, interface and
implementation, with private inheritance being used for the
latter, and a realization that containment is usually
preferrable to inheritance for implementation.  

what about abstract base classes? How do they fit in?
Suppose the OP had an abstact base class

class Drawable;

Then things like Circles, Rectangles, BezierBlobs etc.
all derive from Drawable. The container he's dynamic casting
is a container of Drawable*s. Are those concrete shapes violating
LSP? They do things in addition to the original base class
contract.
 
L

Leslaw Bieniasz

If neither approach seems feasible then consider the knowledge distribution
of your design. The need for casting arises because the knowledge needed for
some action isn't present where the responsibility for carrying out the
action has been assigned. The trick is then to make the knowledge available
where it's needed, by moving or referencing the knowledge and/or the action
responsibility.

Alf,

I like the above idea, but can't you be more specific?
If we take the example of the drawing shapes problem,
mentioned by someone, with additional feature "radius"
of the "circle" object, then how would this redistribution
of knowledge would look like, if the task is to retrieve
the radii from all circle objects present in a list
together with other objects?

Leslaw
 
A

Alf P. Steinbach

* Leslaw Bieniasz:
Alf,

I like the above idea, but can't you be more specific?
If we take the example of the drawing shapes problem,
mentioned by someone, with additional feature "radius"
of the "circle" object, then how would this redistribution
of knowledge would look like, if the task is to retrieve
the radii from all circle objects present in a list
together with other objects?

Oh.

First, you should consider what you're trying to retrieve those radius values
*for*. It's likely to be some generic action, like drawing, that simply
corresponds to a virtual routine in a base class. This is shown below:


<code>
#include <stddef.h>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

class S
{
private:
ostringstream stream;
public:
template< typename T >
S& operator<<( T const& v )
{
stream << v;
return *this;
}
operator string() const { return stream.str(); }
};

template< typename T, ptrdiff_t N >
ptrdiff_t nElements( T const (&)[N] ) { return N; }

class Canvas
{
public:
void draw( string const& s )
{
cout << "Drawing a " << s << endl;
}
};

class Shape
{
protected:
virtual ~Shape() {}
public:
virtual void displayOn( Canvas& aCanvas ) {}
virtual void destroy() { delete this; }
};

class Rectangle
: public Shape
{
private:
int myWidth, myHeight;
protected:
virtual ~Rectangle() {}
public:
Rectangle( int w, int h ): myWidth( w ), myHeight( h ) {}
int w() const { return myWidth; }
int h() const { return myHeight; }
virtual void displayOn( Canvas& aCanvas )
{
aCanvas.draw( S() << "Rectangle(" << w() << "," << h() << ")" );
}
};

class Circle
: public Shape
{
private:
int myRadius;
protected:
virtual ~Circle() {}
public:
Circle( int r ): myRadius( r ) {}
int radius() const { return myRadius; }
virtual void displayOn( Canvas& aCanvas )
{
aCanvas.draw( S() << "Circle(" << radius() << ")" );
}
};

int main()
{
Shape* shapes[] = {new Rectangle(1,2), new Circle(3), new Circle(4)};

for( int i = 0; i < nElements( shapes ); ++i )
{
Canvas canvas;
shapes->displayOn( canvas );
}

for( int i = 0; i < nElements( shapes ); ++i ) { shapes->destroy(); }
}
</code>


But if you're really interested in just the radius values, perhaps to generate
statistics (!) (I can't come up with anything better!), then this is a typical
visitor pattern.

Generally use of the visitor pattern involves dynamic casting but *centralized*
at a single point. However, when you know all possible classes up front then you
can completely avoid casting. This is shown below.


<code>
#include <stddef.h>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

template< typename T, ptrdiff_t N >
ptrdiff_t nElements( T const (&)[N] ) { return N; }

class Rectangle;
class Circle;

class Shape
{
protected:
virtual ~Shape() {}
public:
struct Visitor
{
virtual ~Visitor() {};
virtual void process( Shape& ) {}
virtual void process( Rectangle& r ) { process( (Shape&)r ); }
virtual void process( Circle& r ) { process( (Shape&)r ); }
};

virtual void accept( Visitor& visitor ) { visitor.process( *this ); }
virtual void destroy() { delete this; }
};

class Rectangle
: public Shape
{
private:
int myWidth, myHeight;
protected:
virtual ~Rectangle() {}
public:
virtual void accept( Visitor& visitor )
{
visitor.process( *this );
}

Rectangle( int w, int h ): myWidth( w ), myHeight( h ) {}
int w() const { return myWidth; }
int h() const { return myHeight; }
};

class Circle
: public Shape
{
private:
int myRadius;
protected:
virtual ~Circle() {}
public:
virtual void accept( Visitor& visitor )
{
visitor.process( *this );
}

Circle( int r ): myRadius( r ) {}
int radius() const { return myRadius; }
};

int main()
{
Shape* shapes[] = {new Rectangle(1,2), new Circle(3), new Circle(4)};

struct RadiiCollector: Shape::Visitor
{
virtual void process( Circle& c )
{
cout << "Circle with radius " << c.radius() << endl;
}
};

RadiiCollector rc;
for( int i = 0; i < nElements( shapes ); ++i )
{
shapes->accept( rc );
}

for( int i = 0; i < nElements( shapes ); ++i ) { shapes->destroy(); }
}
</code>


Look ma, no casts. :)


Cheers & hth.,

- Alf


PS: Please don't mail me your Usenet group replies, as you did. I could
mistakenly have responded to the mail before discovering the article in the
group. TIA.
 
K

Keith H Duggar

That's not true. His problem is that class B is not just a
class A; it's a class A and something more. That, in itself,
frequently occurs, even in the best designs. There's certainly
nothing wrong per se with a concrete class implementing several
different interfaces.

Yeah it seems there was a typo or logical error on Noah's part
Ie did he mean to say

'A "is not" a B'

? because clearly in the LSP sense they have been chatting about

"B is-a A"

given the B inherits (publicly) from A scenario described (and
absent information to the contrary such as B breaking semantics
of A).

KHD
 
J

James Kanze

what about abstract base classes? How do they fit in?

If you're inheriting from an abstract base class, you're usually
inheriting interface, not implementation. (There are, perhaps,
some exceptions when the template method pattern is used, but
even then, I wouldn't consider that inheriting implementation in
the classical sense, but rather customizing an existing
implementation.)
Suppose the OP had an abstact base class
class Drawable;
Then things like Circles, Rectangles, BezierBlobs etc. all
derive from Drawable. The container he's dynamic casting is a
container of Drawable*s. Are those concrete shapes violating
LSP? They do things in addition to the original base class
contract.

Yes, but I rather suspect that they should have a common
interface. I don't quite see any need for dynamic_cast when
dealing with such a hierarchy.
 
N

Noah Roberts

(e-mail address removed)>,
(e-mail address removed) says...
what about abstract base classes? How do they fit in?
Suppose the OP had an abstact base class

class Drawable;

Then things like Circles, Rectangles, BezierBlobs etc.
all derive from Drawable. The container he's dynamic casting
is a container of Drawable*s. Are those concrete shapes violating
LSP? They do things in addition to the original base class
contract.

Do they? I find that drawables really don't differ very much. You
might have a hit test, a draw() function, extents() maybe...not much
else. At any rate whatever behavior you have in drawables is pretty
much universal in that they all implement the same thing in different
ways.

The way they differ is in the method you create them. This is why you
of course separate drawable from its creation.

Now, I do have a very similar problem in a real-world application I'm
working on. Not that these drawables have different behavior but that
they represent objects that are not "drawable". I have to put them into
a boost::graph structure. When the user selects one to edit I need to
provide unique edit interfaces for each.

Now, I don't like the idea of embedding the edit behavior in the object
and prefer not to have the object depend on the edit behavior at all.
In other words, the object that is editing X must not be known by X.
The reason for this is that the method of editing is more generally
going to be the thing that is changed or could have multiple methods.

So, I do need to be able to see what type I'm looking at and then supply
the appropriate editor. There's of course one direction you could take:

switch (selected_object.type())
{
case X:
cast to ?? and create editor....
case Y:
....
}

However, why do that when the RTTI does basically the same thing?
Furthermore, this switch can end up appearing in multiple places. Yet
further I may need to override the editor creation method.

Enter the visitor as described in _Modern C++_:

struct visitor { virtual ~visitor(); };

template < typename Visited >
struct visitor_base
{
virtual visit(Visited & v) = 0;
};

#define IMPLEMENT_ACCEPT(type) \
void accept(visitor & vis) \
{ \
if (visitor_base<type> * my_vis = \
dynamic_cast< visitor_base<type> * >(&vis)) \
{ \
my_vis->visit(*this); \
} \
}

struct visited_x
{
IMPLEMENT_ACCEPT(visited_x)
};

This puts the dynamic_cast<> into a cubby hole behind an abstraction. I
then build visitors like so:

struct count_x_and_y : visitor_base<x>, visitor_base<y>
{
int x_count, y_count;
count_x_and_y() : x_count(), y_count() {}

void visit(x & var) { ++x_count; }
void visit(y & var) { ++y_count; }
};

If I pass this into a pile of objects that contain x, y, and z objects
then it will count x and y but not z.

I do tend to try and avoid dynamic_cast all together but when you
honestly need something like this then I generally prefer to put it
behind some sort of abstraction. I've found this kind of thing works
fairly well though there have been some issues when it comes to unit
testing (visitors tend to be coupled to a lot of stuff).

And the end of the day you're simply going to have to balance all the
mutually exclusive principles you need to apply in order to accomplish
your goal. Each and every principle has a very good reason for
existing, it's just not generally possible to perfectly apply them all.
 
N

Noah Roberts

Really? Let's just review the alternatives:

On one hand, you are required to invoke dynamic_cast<> all over the place.
You are required to check the result of the dynamic_cast<>, every time. If
you end up with a null pointer, you must explicitly handle the error
condition, every time.

On the other hand, virtual methods are now invoked in the superclass,
instead. If the superclass is not an instance of an appropriate subclass,
the default implementation in the superclass ends up throwing an exception.
It may come as a shock to the junior apprentices, but they do not need to
catch an exception from every occurence of the virtual method call, that may
potentially throw an exception.

Oh??

Do you know what happens when an exception is thrown but never caught?
If not, then you should be listening rather than advising. At any rate
I think I'll just suggest you go get some better practices. You're
backing up your argument for a poor practice with yet further poor
practices (inadiquate error handling).
 
A

Andreas Dehmel

[snipped previous discussion about dynamic_cast]

Andreas said:
In
something like a drawing program you have objects and their position
on the drawing stack. Type has nothing to do with position, hence any
operation which has to honour stack position (like drawing or finding
the topmost object via graphical positions) has to process N lists
interleaved rather than just one (in which you'd get the stack position
entirely for free). Stack positions have to be unique, so you'll have to
guarantee that over N lists.

Maybe I should elaborate my point of view a little bit: When I said
that I wanted to store the objects in multiple lists, I did not mean
that the original list should be discarded:

And I already said (in the paragraph you quoted below) that this is a
bad idea because redundancy is the germ of inconsistency. Even something
as superficially simple as keeping two lists in sync quickly ceases to
be so in the presence of things like out-of-memory errors. Then you'll
usually have to process twice as many objects whenever the list changes
(object insertion or deletion). For instance if you want to delete an
object you'll have to search it not only in the generic container but
all the other ones as well. Yes, all the other ones, because member
functions like isCircle(), isBezier() etc. which could be used as a
shortcut are actually equivalent to dynamic casts and without that you
won't know which specialization container to check for (in contrast to
creation, one usually doesn't know the type of the "active" object).
The runtime complexity isn't the main problem, you could at least
reduce that with something like a map rather than a list, but the
additional code is. Then there are operations which have to use
specific properties of an object without knowing the type (very
common, usually the "active" object). Algorithm complexity for M
specializations and N objects using dynamic cast: O(1) (since M is
usually fixed at link time). Algorithm complexity for the multi-
container-approach will usually boil down to searching the containers,
so O(N) for your naive list apprach, O(log(N)) for maps. Messing up
complexity classes -- a sure sign of misdesign. I really wouldn't
recommend going there.


[...]
Right. Now we are getting to some constraints that have not been
mentioned yet.

They haven't been excluded either, so why would you assume everything's
fixed?
Libraries that must facilitate for extensions may be a
reason why one should have to use dynamic_casts, although I am not
sure why the drawing program should be such a candidate. Consider
this: If the user wants to add a geometric object of unknown type, the
application can do nothing with it except things that are provided by
the base interface CGeometricObject. So there is no need to keep a
special list for the new type.

Not necessarily true. A library user could use the library infrastructure
for managing the objects, but only feed it his own specializations
which know about each other. I generally consider library writers who think
they know every way their lib can be used and needlessly finalize large
parts of it 1) usually simply lacking imagination and 2) a major pain
in the butt. At least once we leave the realm of trivialities like
yet-another-container-class.

[snip]
It gets really great for something
like "Does A intersect B" (and I don't mean bounding boxes but the
real deal which needs to know the exact properties of both shapes,
e.g. circle and bezier curve). Trying to do this with N containers
and without dynamic casts would mean N^2 implementations of the entire
code sequence from retrieving the objects from their respective
containers based on some criteria (usually not type-related) to the
actual evaluation of the intersection function (N functions, actually,
one for each type).

I don't think that this is true. I would just add the following method
to the base interface:
bool Intersects (const CGeometricObject* Other) const = 0;
Now I can add a method to CPaintApplication that computes all
intersections:
std::list<std::pair<CGeometricObject*,CGeometricObject*> >
ComputeIntersections ()
{
std::list<std::pair<CGeometricObject*,CGeometricObject*> > RetVal;
for (std::list<CGeometricObject*>::iterator first =
GeometricObjects.begin ();
first != GeometricObjects.end (); ++first)
{
std::list<std::pair<CGeometricObject*,CGeometricObject*> > RetVal;
for (std::list<CGeometricObject*>::iterator first =
GeometricObjects.begin ();
first != GeometricObjects.end (); ++first)
{
std::list<CGeometricObject*>::iterator second = first;
++second;
for (; second != GeometricObjects.end (); ++second)
{
if ((*first)->Intersects (*second))
RetVal.push_back (
std::pair<CGeometricObject*,CGeometricObject*>
(*first, *second));
}
}
return RetVal;
}
}


I'm not too hot about finalizing the design the way you have to in order
to make double dispatch work. Apart from the non-extensibility it would work,
but the resulting interface once you realize it's not just Intersects() but
10 other functions which need the same treatment is not something I'd want
to use. And from a maintenance point of view: if I have to change the
interface because I find I'll need other/additional parameters down the line
I'll have to change M methods rather than one. While I'd concede this
technique has its uses in some situations I don't think the advantages
outweigh the disadvantages in cases like this.


[snip long sample code]
What do you think?

I think you have way too much free time ;-). I'm also convinced that
attempting to implement such a multi-container design for an actual drawing
program, widget library or similar rather than heavily idealized, stripped-down
example code, won't survive its own weight long enough to finish the first step,
let alone run the mile. Or can anyone show me a successful, fully-fledged
implementation?



Andreas
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top