BigA BigA - 1 month ago 7
C++ Question

Difficulty in understanding C-style typecasting and dynamic cast

I have been trying to understand type casting in C++. In the following code class B is child class of class A and both share polymorphic relationship.

#include <iostream>
using namespace std;
class A{
int a;
virtual void sayhello() {cout<<"Hello from A"<<endl;}
class B:public A{
int b;
void sayhello(){cout<<"Hello from B"<<endl;}
void another_func(){cout<<"Hello from B::another_func"<<endl;}
int main() {

A *temp1 = new A;
//Statement 1
B *b =(B*) temp1;

//Statement 2
//B* b = dynamic_cast<B*>(temp1);


delete temp1;
return 0;

OUtput of above program -

Hello from B::another_func

I have difficultly in understanding the following issues -

1) For statement 1 How can we cast a parent object to child object.Logically this should be incorrect as now we have widened the capabilities of this object(the same object can now access the child class function another_func).

A similar code in Java produces an error-

"incompatible types: A cannot be converted to B

B b = (A)temp;"

Now if we comment statement 1 & uncomment statement 2 a similar thing happens for statement 2.

So, Why does C++ allows this?

2) Now if we remove sayhello() function from both classes such that they do not have a polymorphic relationship the statement 2 that is dynamic_cast no longer works(as we know dynamic_cast can downcast polymorphic classes) but c-style cast that is statement 1 still produces the same output.

So we can say that c-style cast is not based on polymorphic relationship between classes.
What are the parameters based on which c-style cast happens?


Suppose you toggle the comments so that the C-style cast is commented, and the dynamic_cast is uncommented. Furthermore, modify the code so it is:

B* b = dynamic_cast<B*>(temp1);
if(b == nullptr)
    cout << "not really a B" << endl;

Then when running the code, it prints out "not really a B".

If you look at what dynamic_cast does

If the cast is successful, dynamic_cast returns a value of type new_type. If the cast fails and new_type is a pointer type, it returns a null pointer of that type.

So your version using dynamic_cast was undefined behavior, since you dereferenced the pointer without checking whether the cast failed.

Now to all the different versions using the C-Style cast. The rules are:

When the C-style cast expression is encountered, the compiler attempts to interpret it as the following cast expressions, in this order:

a) const_cast(expression);

b) static_cast(expression), with extensions: pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier). Same applies to casting pointer to member to pointer to member of unambigous non-virtual base;

c) static_cast (with extensions) followed by const_cast;

d) reinterpret_cast(expression);

e) reinterpret_cast followed by const_cast. The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled (see example). If the cast can be interpreted in more than one way as static_cast followed by a const_cast, it cannot be compiled.

According to these rules, your C-style cast is equivalent to

B *b = static_cast<B *>(temp1);

Since temp1 actually points to an A object, this is undefined behavior as well (but for a different reason).

Some general points:

  1. C++ casts are a fine-grained version of C-style casts. If you must cast, prefer them. You can convey to the compiler what aspect you're casting.

  2. You probably should try to avoid casting in any case. If you do use dynamic_cast, check the result.