Re: dynamic_cast does not work as specified



It is not at all clear from the documentation that expression is required to be in the
inheritance chain of type-id (yes, I see now that I can cast to a void*; I'd read it the
other way...)

Consider if I did
SubThing * p = (SubThing*)pHint;
then p is a pointer to an object (ideally) of type SubThing. But I wanted the additional
typecheck to be done to tell me if the thing that is pointed to is of type (SubThing).

What is interesting is that casting to LPVOID makes it work; this points out once again
the horror of OnUpdate/UpdateAllViews using a CObject* instead of an LPVOID. My suspicion
was that since CObject* was not part of the hierarchy it was failing, but the
documentation does not at all make this clear. The phrase at the end

If type-id is a pointer to an unambiguous accessible direct or indirect base class of
expression, a pointer to the unique subobject of type-id is the result

is not stated as a limitation, but what will happen if typeid is a superclass of
expression's type; it does not suggest what happens if typeid is or is not a subclass of
expression's type.

The statement exists

When you use dynamic_cast<typeid>(expression), if expression cannot be safely converted to
type type-id, the run-time check causes the cast to fail.

But in my case, CObject* is a pointer to a type which *is* an object of class Thing, and
in fact an object of class SubThing, just unfortunately disguised as a CObject* due to bad
design (given the pointer is passed transparently from the UpdateAllViews to the OnUpdate
handler, making it other than LPVOID was clearly a design error; in all the years I've
used MFC, I've never passed anything derived from CObject* via this mechanism...but I was
trying to do some "safe casting" here...).

It would be nice to see a more formal description of the semantics of dynamic_cast instead
of the demonstration-by-unreadable-example technique currently used.
joe

On Mon, 12 Jan 2009 00:18:20 -0500, Joseph M. Newcomer <newcomer@xxxxxxxxxxxx> wrote:

Here's a problem I hit that is inconsistent with the documentation.

I'm handling an OnUpdate notification, where the CObject* can be one of several types
depending on the value of lHint.

So the code is basically

void CMyView::OnUpdate(CView * pSender, LPARAM lHint, CObject *pHint)
{
if(lHint == 0 && pHint == NULL)
{ /* normal update */
CView::OnUpdate(pSender, lHint, pHint);
return;
} /* normal update */

if(lHint == WHATEVER)
{ /* update the whatever */
SubThing * p = dynamic_cast<SubThing *>pHint;
ASSERT(p != NULL);
if(p != NULL)
DoSomething(p);
} /* update the whatever */
} // CMyView::OnUpdate

where I have defined

class Thing { ... };
class SubThing : public Thing { ... };

If I try to single-step into it, it tries to trace a source file along some bizarre path
for rtti.cpp, but this source is not included in the distribution. Bummer.

So, I thought, it might have to do with the fact that (due to exceptionally poor design
decisions in the original MFC design) the pHint is declared to be a CObject*, unrelated to
a Thing or SubThing (in a rational world, it would have been an LPVOID). The line

SubThing * p = dynamic_cast<SubThing *>pHint;

generates the compile-time diagnostic:
C2681: 'CObject *': invalid expression type for dynamic_cast

I have no idea why this is an invalid expression for dynamic_cast. But it may deal with
some obscure, undocumented rule.

But dynamic_cast is defined to work on, among other expressions, a pointer-to-void, so I
tried

LPVOID ptr = (LPVOID)pHint;
SubThing * p = dynamic_cast<SubThing *>p;

but that produces an error
C2681: 'LPVOID': invalid expression type for dynamic_cast

in spite of the documetnation of dynamic_cast, which *clearly* states:

The type-id must be a pointer or a reference to a previously defined class type or
a "pointer to void".

It turns out I can get around this by doing

Thing * ptr = (Thing *)pHint;
SubThing * p = dynamic_cast<SubThing *>ptr;

So does this represent an error in the documentation, or an error in the implementation?
joe
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.


Loading