Difference between static and dynamic cast - c++

The class is polymorphic.
Why do both print the same output?
class A
{
public:
virtual void P(){ cout << "A" << endl; }
};
class B : public A
{
public:
void P()override{
cout << "B" << endl;
}
B(){ cout << "Created B" << endl; s = "Created by B"; }
string s;
};
And main:
Variant 1:
A* a = new B(); // Created B
B* b = static_cast<B*>(a);
b->P(); B
cout<<b->s<<endl; // Created by B
And variant 2:
A* a = new B();
B* b = dynamic_cast<B*>(a);
if (b){
b->P();
cout << b->s << endl; // Prints same
}

Both of your examples will do the same thing, and that's fine. Try with this instead:
A* a = new A();
In this case, the static_cast will "succeed" (though it is undefined behavior), whereas the dynamic_cast will "fail" (by returning nullptr, which you already check for).
Your original examples don't show anything interesting because they both succeed and are valid casts. The difference with dynamic_cast is that it lets you detect invalid casts.
If you want to know how dynamic_cast does this, read about RTTI, Run Time Type Information. This is some additional bookkeeping that C++ does in certain cases to inspect the type of an object (it's important for this and also if you use typeid()).

In this case, static_cast is semantically equivalent to dynamic_cast.
static_cast < new_type > ( expression )
2) If new_type is a pointer or reference to some class D and the
type of expression is a pointer or reference to its non-virtual base
B, static_cast performs a downcast. Such static_cast makes no
runtime checks to ensure that the object's runtime type is actually D,
and may only be used safely if this precondition is guaranteed by
other means, such as when implementing static polymorphism. Safe
downcast may be done with dynamic_cast.
dynamic_cast < new_type > ( expression )
5) If expression is a pointer or reference to a polymorphic type Base,
and new_type is a pointer or reference to the type Derived a run-time
check is performed:
a) The most derived object pointed/identified by expression is
examined. If, in that object, expression points/refers to a public
base of Derived, and if only one subobject of Derived type is derived
from the subobject pointed/identified by expression, then the result
of the cast points/refers to that Derived subobject. (This is known as
a "downcast".)
[...]
c) Otherwise, the runtime check fails. If the
dynamic_cast is used on pointers, the null pointer value of type
new_type is returned. If it was used on references, the exception
std::bad_cast is thrown.
The last clause is what makes dynamic_cast safer, as you can check if the cast was unsuccessful:
Base* b1 = new Base;
if(Derived* d = dynamic_cast<Derived*>(b1))
{
std::cout << "downcast from b1 to d successful\n";
d->name(); // safe to call
}

Related

to get the real type information of a pointer in c++

class myclass1 {
public:
virtual ~myclass1() {
}
};
class myclass2 : public myclass1 {
};
int main() {
myclass1 obj1;
myclass2 obj2;
myclass1 *p1 = &obj2;
myclass2 *p2 = static_cast<myclass2 *>(&obj1);
if( p1 && p2){
cout << typeid(p1).name() << endl;
cout << typeid(p2).name() << endl;
}
}
The output is as below:
P8myclass1
P8myclass2
Process finished with exit code 0
The code has two classes, I tried to use two types pointer to point to the other type. From base class to its children is totally ok while the other way around should not work ("myclass2 *p2 = static_cast<myclass2 *>(&obj1);"). If I use "dynamic_cast", the casted pointer will be null. But if I use "static_cast", the cast seems successful and the type is "myclass2" when I use typeid method.
When I am in debug mode in Clion, it seems the debugger knows the real type of the pointer, as shown in the image. It knows the type of p1 is "myclass2" and type of p2 is "myclass1". What is the magic of it?
obj1 = {myclass1}
obj2 = {myclass2}
p1 = {myclass2 * | 0x7ffeec114a08} 0x00007ffeec114a08
p2 = {myclass1 * | 0x7ffeec114a10} 0x00007ffeec114a10
typeid(p1) will give you the type of the pointer p1, which will always be myclass1 * (the string P8myclass1 is the mangled name for the type myclass1 *). If you want the type of the pointed-at object, you want typeid(*p1), which should be myclass2 in this case.
With p2, typeid(p2) will be myclass2 *, while typeid(*p2) gives undefined behavior -- you can't safely dereference a pointer after a static cast to the wrong type. It is likely that you'll get myclass1, but not certain -- you might get a crash.
The debugger is essentially doing that with extra knowledge and protection to avoid bad misbehavior from the undefined behavior.
The "magic" is likely undefined behaviour. You can't static_cast a pointer to point to a different type except in specific situations (like an upcast). In your case, &obj1 points to a myclass1 object, not a myclass2 object, so it is completely meaningless to perform the downcast.

Value cast vs Reference cast

What is the difference between value cast and reference cast? Why one of them invokes conversion (aka creating new object) and other doesn't? What are caveats of using casting on rhs?
Assume this is Derived . Why those will not actually cast to Base?
*this = (Base&) rhs
(Base)* this = rhs
Could you please show on simple examples?
Value cast creates a new value from an existing one; reference cast creates a new reference to the same existing value.
Reference cast neither changes the content of an existing object nor creates a new one; it is restricted to changing the interpretation of the value that is already there. Value casting, on the other hand, can make a new object from an existing one, so it has fewer restrictions.
For example, if you have an unsigned char and you want a value or a reference of type int, value cast is going to work, while reference casting is going to fail:
unsigned char orig = 'x';
int v(orig); // Works
int &r(orig); // Does not work
rhs is Derived, I want to assign all inherited and non-inherited stuff from rhs into Base
Then you need to cast both sides to Base, or add an assignment operator to Derived that takes a const Base& as an argument. Here is an example of casting on both sides (may be hard to understand by other programmers reading your code)
struct Base {
int x;
Base(int x) : x(x) {}
};
struct Derived1 : public Base {
Derived1(int x) : Base(x) {}
};
struct Derived2 : public Base {
Derived2(int x) : Base(x) {}
};
Running the code below
Derived1 d1(5);
Derived2 d2(10);
cout << d1.x << " " << d2.x << endl;
((Base&)d1) = (Base&)d2;
cout << d1.x << " " << d2.x << endl;
produces the following printout:
5 10
10 10
As you can see, the assignment ((Base&)d1) = (Base&)d2 copied the content of d2's Base portion into d1's Base portion (demo).
What is the difference between value cast and reference cast?
Value casts convert an object to the value:
char i = 'a';
int k = static_cast<int>(i); // Prefer C++ casts to C casts
Reference casts convert an object to a reference:
char i = 'a';
int &k = static_cast<int&>(i);
Just because the conversion can be done implicitly in int &k = i doesn't mean it doesn't happen.
Why one of them invokes conversion (aka creating new object) and other doesn't?
If you write int &x = static_cast<int&>(i), there are 2 things that can happen:
1) A pointer is created pointing to i (references are hidden pointers). Then this hidden pointer gets assigned to x, and x behaves as a reference of i.
2) Usually, the compiler optimizes away this reference, and simply considers x an alias of i. Therefore no variable is instantiated.
In the former case, a new object is created.
However, if you write:
char c = 'a';
int i = static_cast<int> (c);
there is no instantiation, just a copy of the memory from c to i.
Why those will not actually cast to Base?
*this = (Base&) rhs
You cannot assign the base object to a derived object, only the opposite. This will most likely overwrite the fields of the base object to the derived object's.
(Base)* this = rhs
There is no point in castling an l-value. This is equivalent to:
*this = rhs;
What are caveats of using casting on rhs?
I don't think there is anything wrong with casting, as long as they do not decrease readability.

Downcasting using dynamic_cast returns null

I'm trying to cast a base class object to a derived class object with dynamic_cast, but dynamic_cast returns null. Is it possible to downcast using dynamic_cast?
struct A {
virtual ~A() {}
};
struct B : A {};
int main()
{
A* a = new A();
B* b = dynamic_cast<B*>(a);
if(b){
std::cout << "b has value" << std::endl;
}else{
std::cout << "no value" << std::endl;
}
}
This code prints out "no value".
Because a is pointing to A in fact, not a B, then dynamic_cast will fail.
Is it possible to downcast using dynamic_cast?
Yes, you can, e.g. if a points to B exactly,
A* a = new B;
B* b = dynamic_cast<B*>(a);
See http://en.cppreference.com/w/cpp/language/dynamic_cast
5) If expression is a pointer or reference to a polymorphic type Base, and new_type is a pointer or reference to the type Derived a run-time check is performed:
a) The most derived object pointed/identified by expression is examined. If, in that object, expression points/refers to a public base of Derived, and if only one subobject of Derived type is derived from the subobject pointed/identified by expression, then the result of the cast points/refers to that Derived subobject. (This is known as a "downcast".)
...
c) Otherwise, the runtime check fails. If the dynamic_cast is used on pointers, the null pointer value of type new_type is returned. If it was used on references, the exception std::bad_cast is thrown.
That is per design. dynamic_cast is used when you want to test whether a pointer to a base class object actually points to a subclass or not. If it is a subclass object, the dynamic_cast will give you a valid pointer, and if it is not, you just get a nullptr.
As you created a A class object, and and A is not a subclass of B, the dynamic_cast normally returned a null pointer.

Downcasting a class c++

I have a doubt about downcasting an object in C++.
Here it comes an example:
class A { }
class B : public A {
public:
void SetVal(int i) { _v = i; }
private:
int _v;
}
A* a = new A();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
What would it happen with this example? We are modifying a base clase like if it is a child one... how does it work related with the memory?
With this cast... Is it like creating an instance of B and copying the values of A?
Thanks
A* a;
This just gives you a pointer to an A. It doesn't point anywhere in particular. It doesn't point at an A or B object at all. Whether your code works or not depends on the dynamic type of the object it is pointing at.
So there are two situations you might want to know about. First, this one:
A* a = new A();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
This will give you undefined behaviour because the dynamic_cast will return a null pointer. It returns a null pointer when the dynamic type of the object is really not a B. In this case, the object is an A. You then attempt to dereference the null pointer with b->SetVal(2), so you get undefined behaviour.
A* a = new B();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
This will work fine because the object really is a B object. The dynamic cast will succeed and the SetVal call will work just fine.
However, note that for this to work, A must be a polymorphic type. For that to be true, it must have at least one virtual member function.
That shouldn't even compile, because the classes aren't polymorphic so you can't use dynamic_cast.
If it did, it would be undefined behavior.

Why is it undefined behavior to delete[] an array of derived objects via a base pointer?

I found the following snippet in the C++03 Standard under 5.3.5 [expr.delete] p3:
In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
Quick review on static and dynamic types:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D();
Static type of p is B*, while the dynamic type of *p is D, 1.3.7 [defns.dynamic.type]:
[Example: if a pointer p whose static type is “pointer to class B” is pointing to an object of class D, derived from B, the dynamic type of the expression *p is “D.”]
Now, looking at the quote at the top again, this would mean that the follwing code invokes undefined behaviour if I got that right, regardless of the presence of a virtual destructor:
struct B{ virtual ~B(){} };
struct D : B{};
B* p = new D[20];
delete [] p; // undefined behaviour here
Did I misunderstand the wording in the standard somehow? Did I overlook something? Why does the standard specify this as undefined behaviour?
Base* p = new Base[n] creates an n-sized array of Base elements, of which p then points to the first element. Base* p = new Derived[n] however, creates an n-sized array of Derived elements. p then points to the Base subobject of the first element. p does not however refer to the first element of the array, which is what a valid delete[] p expression requires.
Of course it would be possible to mandate (and then implement) that delete [] p Does The Right Thing™ in this case. But what would it take? An implementation would have to take care to somehow retrieve the element type of the array, and then morally dynamic_cast p to this type. Then it's a matter of doing a plain delete[] like we already do.
The problem with that is that this would be needed every time an array of polymorphic element type, regardless of whether the polymorphism is used on not. In my opinion, this doesn't fit with the C++ philosophy of not paying for what you don't use. But worse: a polymorphic-enabled delete[] p is simply useless because p is almost useless in your question. p is a pointer to a subobject of an element and no more; it's otherwise completely unrelated to the array. You certainly can't do p[i] (for i > 0) with it. So it's not unreasonable that delete[] p doesn't work.
To sum up:
arrays already have plenty of legitimate uses. By not allowing arrays to behave polymorphically (either as a whole or only for delete[]) this means that arrays with a polymorphic element type are not penalized for those legitimate uses, which is in line with the philosophy of C++.
if on the other hand an array with polymorphic behaviour is needed, it's possible to implement one in terms of what we have already.
It's wrong to treat an array-of-derived as an array-of-base, not only when deleting items. For example even just accessing the elements will usually cause disaster:
B *b = new D[10];
b[5].foo();
b[5] will use the size of B to calculate which memory location to access, and if B and D have different sizes, this will not lead to the intended results.
Just like a std::vector<D> can't be converted to a std::vector<B>, a pointer to D[] shouldn't be convertible to a B*, but for historic reasons it compiles anyway. If a std::vector would be used instead, it would produce a compile time error.
This is also explained in the C++ FAQ Lite answer on this topic.
So delete causes undefined behavior in this case because it's already wrong to treat an array in this way, even though the type system can't catch the error.
Just to add to the excellent answer of sth - I have written a short example to illustrate this issue with different offsets.
Note that if you comment out the m_c member of the Derived class, the delete operation will work well.
Cheers,
Guy.
#include <iostream>
using namespace std;
class Base
{
public:
Base(int a, int b)
: m_a(a)
, m_b(b)
{
cout << "Base::Base - setting m_a:" << m_a << " m_b:" << m_b << endl;
}
virtual ~Base()
{
cout << "Base::~Base" << endl;
}
protected:
int m_a;
int m_b;
};
class Derived : public Base
{
public:
Derived()
: Base(1, 2) , m_c(3)
{
}
virtual ~Derived()
{
cout << "Derived::Derived" << endl;
}
private:
int m_c;
};
int main(int argc, char** argv)
{
// create an array of Derived object and point them with a Base pointer
Base* pArr = new Derived [3];
// now go ahead and delete the array using the "usual" delete notation for an array
delete [] pArr;
return 0;
}
IMHO this has to do with limitation of arrays to deal with constructor/destructor. Note that, when new[] is called, compiler forces to instantiate only default constructor. In the same way when delete[] is called, compiler might look for only the destructor of calling pointer's static type.
Now in the case of virtual destructor, Derived class destructor should be called first followed by the Base class. Since for arrays compiler might see the static type of calling object (here Base) type, it might end up calling just Base destructor; which is UB.
Having said that, it's not necessarily UB for all compilers; say for example gcc calls destructor in proper order.
I think it all comes down to the zero-overhead principle. i.e. the language doesn't allow storing information about the dynamic type of elements of the array.