Dynamic casting of stack object fails
-
04-06-2021 - |
Pergunta
I came across an instance the other day where I had a function taking a pointer to a base type which I then needed to up-cast to a derived type to access some additional functionality. However, dynamic_cast
failed, which was odd because my type definitely inherited the base type.
To get to the bottom of what was going on, I created the following test program, which I think replicates what I was seeing:
void cast(TestClass *baseType)
{
if (dynamic_cast<Derived *>(baseType))
TRACE("cast was sucessful");
else
TRACE("cast failed");
}
int main(int argc, char *argv[])
{
Derived *test1 = new Derived();
TestClass *test2 = new TestClass();
TestClass test3;
test1->identify(); // prints: this is a Derived class
test2->identify(); // prints: this is a TestClass
cast(test1); // succesful
cast(test2); // fail - expected
// reassign test2 to test1
test2 = test1;
test2->identify(); // prints: this is a Derived class
cast(test2); // succesful
// the interesting part, the test3 object (created on stack), does not cast
// despite that it would seem possible from the cast method.
test3 = *test1;
test3.identify(); // prints: this is a TestClass
cast(&test3); // fails?
return a.exec();
}
Which is interesting, because if you were presented with only the method I called cast()
, you would expect it to be possible to cast the object passed in. I've demonstrated that this isn't the case; it depends on how the object is originally created. What is confusing, is why it is possible to cast an object which has been reassigned by reference but not by value. Furthermore, would using static_cast
work, as long as we guarantee the types are compatible?
Solução
test3
is of type TestClass
(which I assume is the parent of Derived), so the dynamic cast fails.
Even though you assign *test1
to it, the assignment only copies the TestClass
part (aka slicing). When you assign a pointer to a pointer, no slicing occurs.
You can think of derived objects as having a part of their base:
*test1:
|--------------|
|TestClass part|
|--------------|
|Derived part |
|--------------|
test3:
|--------------|
|TestClass part|
|--------------|
When you assign a pointer (test2=test1
), the object itself does not change, you are just looking at it via a different glass (through a pointer to TestClass
), thus casting works.
When you assign an object itself (test3=*test1
), the destination (test3
) has room only for a TestClass
object, so the copy takes away the extra Derived
part.