C++ static_cast vs dynamic_cast - c++

#include <iostream>
class Base {
};
class Derived : public Base {
};
int main() {
Base* bptr = new Derived();
Derived* dptr = static_cast<Derived*>(bptr);
std::cout << dptr << std::endl;
}
In the above code, I should be using dynamic_cast but am using
static_cast incorrectly. static_cast should never be used while
downcasting, since compiler has no way to determine we are doing
cast correctly.
Why isn't this a compile error ? I am using gcc 4.9.2. Do you guys
think this is a bug in the compiler, or does C++ standards allow such code ?
Edit: Thanks for the responses. Actually, Base class above is polymorphic
i.e. it has virtual functions, but I left them out for this example. I should
have thrown in a virtual destructor in the Base to make it clear that it
was polymorphic - my bad.

In the above code, I should be using dynamic_cast but am using static_cast incorrectly. static_cast should never be used while downcasting, since compiler has no way to determine we are doing cast correctly.
Ironically, the dynamic_cast would actually be the ill-formed cast here, since your types are not polymorphic.
That said, static_cast can certainly be used to downcast. You are correct that the compiler cannot do type-checking, but there are many situations in which you have a Base* and know that it points to a Derived*, so you can just manually do the cast. One very common case is CRTP:
template <class Derived>
class Base {
Derived& self() { return *static_cast<Derived*>(this); }
// ...
};
class Foo : Base<Foo> { ... };
Base<T> is always a T, so that downcast is safe.
The advantage of static_cast over dynamic_cast is that static_cast is free but dynamic_cast is expensive. The C++ mantra is don't pay for what you don't need.

static_cast < new_type > ( expression )
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. This downcast is ill-formed if B is
ambiguous, inaccessible, or virtual base (or a base of a virtual base)
of D. 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.
Source (Explanation item 2)

You are using static_cast perfectly correctly. You are right, the compiler can in the general case not know whether the cast is correct, but static_cast is exactly there for this scenario.
You cannot use dynamic_cast here because that cast is for polymorphic classes (those which have a virtual member function). These classes carry run-time information; that information allows the code to choose the correct implementation of that function in the actual type of the object pointed to. This type information in the object can be used by the cast function to determine whether the type conversion is possible, and then indeed perform the conversion properly (which can be tricky with multiple and virtual inheritance).
Classes without virtual functions, like your example classes, do not carry this run time information, and dynamic_cast cannot be used to cast to a more derived type. (It can still be used to cast to the same type or to a base class, i.e. it can be used for conversions which do actually not need a cast.)

Related

Static cast allows conversion of object pointers but not integers

Why does static cast allow an upcast or downcast between pointers to objects derived or base as below, but in the case of casting between a char* and int* or vice versa int* to char*, there is a compilation error?
Casting between different pointers to objects is just as bad I believe.
// compiles fine
class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * bc = static_cast<Derived*>(a);
// Gives an invalid static cast error during compilation
char charVar = 8;
char* charPtr = &charVar;
int* intPtr = static_cast<int*>(charPtr);
C++ is strongly performance oriented. So as long as there is some use case for that you can gain performance, C++ will allow you to do it. Consider std::vector: Sure, there is the safe element access via function at, which does range checking for you. But if you know that your indices are in range (e. g. in a for loop), these range checks are just dead weight. So you additionally get the (less safe) operator[] which just omits these checks.
Similarly, if you have a pointer of type Base, it could, in reality, point to an object of type Derived. If in doubt, you would dynamic_cast from Base* to Derived*. But this comes with some overhead. But if you know 100% for sure (by whatever means...) what the sub class actually is, would you want this overhead? As there is a natural (even implicit!) way from Derived* to Base*, we want to have some low-cost way back.
On the other hand, there is no such natural cast between pointers of totally unrelated types (such as char and int or two unrelated classes) and thus no such low-cost way back (compared to dynamic_cast, which isn't available either, of course). Only way to transform in between is reinterpret_cast.
Actually, reinterpret_cast comes with no cost either, it just interprets the pointer as a different type – with all risks! And a reinterpret_cast even can fail, if instead a static_cast would have been required (right to prevent the question "why not just always use ..."):
class A { int a; };
class B { };
class C : public A, public B { };
B* b = new C();
C* c = reinterpret_cast<C*>(b); // FAILING!!!
From view of memory layout, C looks like this (even if hidden away from you):
class C
{
A baseA;
B baseB; // this is what pointer b will point to!
};
Obviously, we'll get an offset when casting between C* and B* (either direction), which is considered by both static_cast and dynamic_cast, but not by reinterpret_cast...
Why does static cast allow an upcast ...
There is no reason to prevent upcast. In fact, a derived pointer is even implicitly convertible to a base pointer - no cast is necessary (except in convoluted cases where there are multiple bases of same type). A derived class object always contains a base class sub object.
Upcasting is particularly useful because it allows runtime polymorphism through the use of virtual functions.
or downcast between pointers to objects derived or base as below
A base pointer may point to a base sub object of a derived object, as a consequence of an upcast. Like for example here:
Derived d;
Base *b = &d;
There are cases where you may want to gain access to members of the derived object that you know is being pointed at. Static cast makes that possible without the cost of run time type information.
It is not possible in general for the compiler to find out (at compile time) the concrete type of the pointed object (i.e. whether the pointer points to a sub object and if it does, what is the type of the container object). It is the responsibility of the programmer to ensure that the requirements of the cast are met. If the programmer cannot prove the correctness, then writing the static cast is a bug.
That's because what you're trying to do is a reinterpretation - for which there's a reinterpret_cast<> operator. static_cast<> for pointers is only used for down-casting:
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. This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D. 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.
See:
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
for a detailed discussion of when to use each casting operator.

Multiple inheritance cast not working as expected

I recently had a problem with casts and multiple inheritance: I needed to cast a Base* to Unrelated*, because a specific Derived class derives the Unrelated class.
This is a short example:
#include <iostream>
struct Base{
virtual ~Base() = default;
};
struct Unrelated{
float test = 111;
};
struct Derived : Base,Unrelated{};
int main(){
Base* b = new Derived;
Unrelated* u1 = (Unrelated*)b;
std::cout << u1->test << std::endl; //outputs garbage
Unrelated* y = dynamic_cast<Unrelated*>(b);
std::cout << y->test << std::endl; //outputs 111
}
The first cast clearly doesnt work, but the second one did work.
My question is: Why did the second cast work? Shouldnt dynamic_cast only work for cast to a related class type? I thought there wasnt any information about Unrelated at runtime because it is not polymorphic.
Edit: I used colirus gcc for the example.
dynamic_cast works because the dynamic type of object pointed to by a pointer to its base class is related to Unrelated.
Keep in mind that dynamic_cast requires a virtual table to inspect the inheritance tree of the object at run-time.
The C-style cast (Unrelated*)b does not work because the C-style cast does const_cast, static_cast, reinterpret_cast and more, but it does not do dynamic_cast.
I would suggest avoiding C-style casts in C++ code because they do so many things as opposed to precise C++ casts. My colleagues who insist on using C-style cast still occasionally get them wrong.
The first cast (Unrelated*)b doesn't work because you're treating the Base class sub-object, containing probably just a vtable pointer, as an Unrelated, containing a float.
Instead you can cast down and up, static_cast<Unrelated*>( static_cast<Derived*>( b ) ).
And this is what dynamic_cast does for you, since Base is a polymorphic type (at least one virtual method) which allows dynamic_cast to inspect the type of the most derived object.
In passing, dynamic_cast<void*>( b ) would give you a pointer to the most derived object.
However, since you know the types there's no need to invoke the slight overhead of a dynamic_cast: just do the down- and up-casts.
Instead of the C style cast (Unrelated*)b you should use the corresponding C++ named cast or casts, because C style casts of pointers can do things you'd not expect, and because the effect can change completely when types are changed during maintenance.
The C style cast will maximum do 2 C++ named casts. In this case the C style cast corresponds to a reinterpret_cast. The compiler will not allow any other named cast here.
Which is a warning sign. ;-)
In contrast, the down- and up-casts are static_casts, which usually are benign casts.
All that said, the best is to almost completely avoid casts by using the top secret technique:
Don't throw away type information in the first place.
I.e., in the example code, just use Derived* as the type of the pointer.
With multiple inheritance, the Derived object consists of two sub-objects, one Base and one Unrelated. The compiler knows how to access whichever part of the object it needs, typically by adding an offset to the pointer (but that's an implementation detail). It can only do that when it knows the actual type of a pointer. By using a C-style cast, you've told the compiler to ignore the actual type and treat that pointer value as a pointer to something else. It no longer has the information necessary to properly access the sub-object you desire, and it fails.
dynamic_cast allows the compiler to use run-time information about the object to locate the proper sub-object contained within it. If you were to output or examine the pointer values themselves, you'd see that they are different.

static_cast from Derived* to void* to Base*

I would like to cast a pointer to a member of a derived class to void* and from there to a pointer of the base class, like in the example below:
#include <iostream>
class Base
{
public:
void function1(){std::cout<<"1"<<std::endl;}
virtual void function2()=0;
};
class Derived : public Base
{
public:
virtual void function2(){std::cout<<"2"<<std::endl;}
};
int main()
{
Derived d;
void ptr* = static_cast<void*>(&d);
Base* baseptr=static_cast<Base*>(ptr);
baseptr->function1();
baseptr->function2();
}
This compiles and gives the desired result (prints 1 and 2 respectively), but is it guaranteed to work? The description of static_cast I found here: http://en.cppreference.com/w/cpp/language/static_cast
only mentions conversion to void* and back to a pointer to the same class (point 10).
In the general case, converting a base to void to derived (or vice versa) via static casting is not safe.
There will be cases where it will almost certainly work: if everything involved is a pod, or standard layout, and only single inheritance is involved, then things should be fine, at least in practice: I do not have chapter and verse from the standard, but the general idea is that the base in that case is guaranteed to be the prefix of the derived, and they will share addresses.
If you want to start seeing this fail, mix in virtual inheritance, multiple inheritance (both virtual and not), and multiple implementation inheritance that are non trivial. Basically when the address of the different type views of this differ, the void cast from and back to a different type is doomed. I have seen this fail in practice, and the fact it can fail (due to changes in your code base far away from the point of casting) is why you want to be careful about always casting to and from void pointer with the exact same type.
In general, no, it is not safe.
Suppose that casting Derived* directly to Base* results in a different address (for example, if multiple inheritance or virtual inheritance is involved).
Now if you inserted a cast to void* in between, how would the compiler know how to convert that void* to an appropriate Base* address?
If you need to cast a Derived* to a void*, you should explicitly cast the void* back to the original Derived* type first. (And from there, the cast from Derived* to Base* is implicit anyway, so you end up with the same number of casts, and thus it's not actually less any convenient.)
From the link you supplied yourself
9) A pointer to member of some class D can be upcast to a pointer to member of its base class B. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.
Meaning as long as you know that the upcast is safe before you do it it is guaranteed to work. That's why you should be using dynamic_cast which returns nullptr if unsuccessful.
Think of it this way if you have.
Type * t1;
static_cast of t1 to one of the classes deriving from it cannot be known at compile time, without in depth analysis of your program (which obviously it is not and should not be doing), so even if it ends up being correct you have no way of checking. dynamic_cast does extra work at runtime to check if the conversion was successful hence the prefix dynamic.

virtual functions and static_cast

Can i safely call virtual functions after using static_cast on polymorphic class in situations like in the following code or is it UB?
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo() \n"; }
};
class Derived : public Base
{
public:
virtual void foo() { std::cout << "Derived::foo() \n"; }
};
int main()
{
Base* derived = new Derived;
Derived* _1 = static_cast<Derived*>(derived);
_1->foo();
}
Yes, you can. Although I don't see the point of doing that in your specific example. Just calling it as
derived->foo();
without any casts would have produced exactly the same effect. I.e. some sort of static_cast in that case would be performed implicitly by the virtual call mechanism.
Note that your static_cast does not in any way suppress the "virtual" nature of the call.
That actually makes me wonder what your question is really about. Why would you even ask about it? What are you trying to do? In your code sample really representative of what you are trying to do?
If the compiler allows you to static_cast and at run-time the dynamic type of the object is as expected, then yes, you can. The question is why do you want to do that...
Yes, but as others have said, you don't need to cast the pointer to the derived type to call virtual functions.
However, it is usually safer to use dynamic_cast when dealing with inherited classes. Using dynamic_cast will generate the proper errors if the type information is incorrect at runtime.
Derived* d = dynamic_cast<Derived*>(derived); //safer, but still unnecessary in this situation
As written, that's going to work, basically because derived is a Derived*. So, all the cast is doing is telling the compiler what you already know. Then again, even without the static cast, you'll just end up with Derived::foo in your output. So, this is somewhat pointless. Still, you might need to do this in a situation where you're absolutely sure you know the actual instanced type of your variable and you need to access some non-virtual members for some reason. If you're using a badly designed class library, for instance...
But, in general, static downcasts are a bad idea. You might end up trying to downcast a variable that isn't a Derived*, in which case, calling virtual (or non-virtual) functions (or, in fact, using that pointer for almost any non-trivial operation) results in Undefined Behavior.

Can't downcast because class is not polymorphic?

Is it possible to have inheritance with no virtual methods? The compiler is saying that the following code is not polymorphic.
Example:
class A {
public:
int a;
int getA(){return a;};
}
class B : public A {
public:
int b;
int getB(){return b;};
}
In another class we are trying to downcast from an A object to a B object:
A *a = ...;
B *b = dynamic_cast<B*>(a)
but this gives the following compile-time error:
cannot dynamic_cast ... (source type is not polymorphic)
Syntax errors non-withstanding, you cannot dynamic_cast a non-polymorphic type. static_cast is the cast you would use in this case, if you know that it is in fact an object of the target type.
The reason why: static_cast basically has the compiler perform a check at compile time "Could the input be cast to the output?" This is can be used for cases where you are casting up or down an inheritance hierarchy of pointers (or references). But the check is only at compile time, and the compiler assumes you know what you are doing.
dynamic_cast can only be used in the case of a pointer or reference cast, and in addition to the compile time check, it does an additional run time check that the cast is legal. It requires that the class in question have at least 1 virtual method, which allows the compiler (if it supports RTTI) to perform this additional check. However, if the type in question does not have any virtual methods, then it cannot be used.
The simplest case, and probably worthwhile if you're passing pointers around like this, is to consider making the base class's destructor virtual. In addition to allowing you to use dynamic cast, it also allows the proper destructors to be called when a base class pointer is deleted.
You need at least one virtual method in a class for run-time type information (RTTI) to successfully apply dynamic_cast operator.
just make A destructor virtual (always do for any class just for safety).
yes, dynamic_cast for non-polymorphic types are not allowed. The base class shall have at least one virtual method. Only then that class can be called as polymorphic.
This article explains a similar example: http://www.cplusplus.com/doc/tutorial/typecasting/
A a;
B *b = dynamic_cast<B*>(a)
Here a is an object and b is a pointer.
Actually, upcasting and downcasting are both allowed in C++. But when using downcasting, 2 things should be pay attention to:
The superclass should has at least one virtual method.
Since superclass is "smaller" than subclass, one should use memory object carefully.