Re: dynamic_cast
On 20 Nov., 19:01, "Alexander Arhipenko" <arhip...@gmail.com> wrote:
Part 1.
Suppose we have 2 classes:
struct A
{};
struct B : private A
{};
Should following dynamic_cast expression compile or return 0 pointer:
B b;
A* pa = dynamic_cast<A*>(&b);
I think your question is a good one and my answer might be a
little bit like slipping on thin ice. My current interpretation
is that the standard's actually requires this expression to be
ill-formed and I try to reason why I think so - I hope that
others will add their own thoughts. To introduce, my reasoning
bases on the complete [expr.dynamic.cast] section and [conv.ptr]/3,
so maybe I have overlooked something.
- Concerning [expr.dynamic.cast], p.1 and p.2 are clearly fulfilled,
because with A* <=> T and v <=> &b (T and v in the language of this
paragraph) where v is an rvalue of a pointer to a complete class type,
T being a pointer to a complete class type, and the required result
being an rvalue of A*, thus the so-called required result type R is
A*.
- P.3+4 do not apply here, because the value of v is not the null
pointer value nor is R (cv-)equal to the source type.
- P. 5 is actually a critical "barrier", because seemingly our
conditions let us fall into this 'bucket', when it starts with:
"If T is 'pointer to cv1 B' and v has type 'pointer to cv2 D' such
that
B is a base class of D, the result is a pointer to the unique B
sub-object of the D object pointed to by v.[..]"
The key sentence seems to be it's last requirement:
"In both the pointer and reference cases,[..] B shall be an
accessible
unambiguous base class of D."
This last requirement is not fulfilled and makes IMO the expression
ill-formed.
I would like to add at this point that I think that we *cannot*
apply [conv.ptr] (especially p.3) for dynamic_cast, because I cannot
read that dynamic_cast is meant to perform a conversion following
the rules of [conv.ptr], it only returns the *result* of a conversion
(p.1) - I would appreciate others opinions regarding this POV.
Now the other side: My assumption is that VS2005 seems to interpret
the last requirement to be part of the condition to fall into this
bucket. Because this condition is not fulfilled, it goes on with the
next point. At this point I have to ask the english native speekers,
whether such an interpretation is feasible and legal here. For the
moment I will follow this line of alternative reasoning:
- P. 6 applies *only* if v is (in this case) a pointer to a
polymorphic
type. This restriction explains IMO the different behaviour of VS2005
depending on the virtualness of the destructor of A. Since no further
"otherwise" follows, this is the last legal bucket and if that does
not apply, VC2005 interprets the expression as ill-formed. I proceed
with:
Part 2:
Assume we have the same classes, but base class is polymorphic:
struct A
{
virtual ~A() {}};
struct B : private A
{};
Again, should expression with dynamic_cast above compile or return 0
pointer (or should this be implementation defined)?
In short, according to my understanding, this should have the same
result (ill-formed expression) as in part 1, but VS2005 follows
another path, as explained above. To make a long story short, the
compiler applies the run-time check rule of p.8 (p. 7 does not apply)
and falls into the last bullet, saying:
"Otherwise, the run-time check fails."
Note that p. 9 says that
"The value of a failed cast to pointer type is the null pointer value
of the required result type.[..]"
and consequently the VS2005 program returns a null pointer value.
Now the fun side - and actually the reason for this long explanation
-
is the immediatly following example with the following relevant lines:
"[..]
class B { virtual void g(); };
class D : public virtual A, private B {};
[..]
D d;
[..]
bp = dynamic_cast<B*>(&d); // fails
[..]"
Note that the comment says "fails" according to the nomenclature
of p.8, and it does not say "ill-formed" as done only some lines
later in another situation, where another expression definitively
*is* ill-formed.
If my interpretation is correct, this comment should be changed
as part of an editorial fix to say:
"// ill-formed: base class is inaccessible"
otherwise all other compilers (gcc 3.4.1, Comeau, ..) need to be
fixed.
But I've found following snip of code in
Bjarne Stroustrup's C++PL (15.4.1) that makes me confusing:
BBslider* pbb2 = dynamic_cast<BBslider*>(p); //ok: pbb2 becomes 0
According to my interpretation this comment is wrong, but
I also think that the standard could more clearer express
its intend. Also note that this example is rather similar
to the - IMO also incorrect - example given in the standard.
I checked the most recent draft N2461 and - except for minor
adaptions to rvalue references - I could not find wording
changes that influence the outcome of your example.
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]