Is it possible to downcast an object to a subclass does not define any extra variable or virtual method?
If I have these classes,
class A { public: A (); };
class B : public A { public: void method1 () {} B (); };
is this (1) possible and (2) safe by standard?
A* a = new A ();
B* b = (B*)a;
b->method1();
The pointer conversion acts as a static_cast
. 5.2.9/2 says,
If the object of type [
A
] is actually a subobject of an object of type [B
], the result refers to the enclosing object of type [B
]. Otherwise, the result of the cast is undefined.
Your object is not a subobject of a B
object, so the result is undefined.
Even if you were to reinterpret_cast
, accessing the value of the object through the resulting pointer has undefined behavior because it violates strict aliasing. In the C++11 standard, 3.10/10:
If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
"A derived class of the dynamic type of the object that adds no data members or virtual member functions" is not in the list that follows.
Depending on what method1
actually does, it might be possible to avoid accessing the stored value of the object when calling it. But I'm not certain it's ever possible. Unless stated otherwise elsewhere in the standard I would assume for safety that calling a non-static member function inherently "accesses the stored value of the object" even if the function doesn't actually use any data members.
This is one of those awkward cases that will probably work in practice either all the time or almost all the time. But it's not guaranteed, so even if it appears to work and the emitted code looks OK, you will live in fear that some day a new optimization will break it.
Once defined, C++ classes are closed to new members, including new member functions. So your object created with new A()
has all the member functions it will ever have. Just write a non-member function -- unless A
has protected
members it will have exactly the same access to A
that your member function has. And if A
does have protected
members then there's an approved way of deriving from it, which you should use to create proper instances of B
.
If member function syntax means that much to you, then depending on the class A
you might be able to write:
B b = *a; // "copy" the object (give B a suitable ctor)
b.method1(); // act on it
*a = b; // copy it back (A needs copy assignment operator)
Obviously there are issues here that could stop it working: to begin with whether the object is copyable, also thread-safety, and whether method1
stores a pointer/reference to b
somewhere that will start to dangle as soon as b
is destroyed. In C++11 the copies could perhaps be moves for efficiency, but even so I hope you will agree that the hoops you have to jump through to use member function syntax are not worth it.
This is more like C void* casting, which is not the best thing to do in C++. But I did this many times and it works fine.
B* b = static_cast< B* >a or what you tried is an unsafe downcasting,it assigns the address of a base-class object (A) to a derived class (B) pointer. So if you access anything throught that pointer, it will cause undefined behavior.
Let's assume one possible object layout of an instance of A:
a ->|vptr|
When you perform a forced cast:
b ->|vptr|
it is definitely unsafe since a doesn't point to an instance of B or subclass of B. When you call a virtual method or modify a field(not in this case), it will cause undefined behavior in general or error in this layout.
However, your method1 is non-virtual, so there is no need to look up virtual table. Since your implementation of the method1 doesn't and even can't do anything on "this", So when you run the code in this hypothetical object layout, it will probabaly report no error(See James' comment).
You should read this extremely well-written post:
Regular cast vs. static_cast vs. dynamic_cast
If you use "static_cast", be warned that you are "force" converting and this is inherently unsafe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With