Why is only static_cast able to return new object of requested type?

554 Views Asked by At

Among static_cast, dynamic_cast, reinterpret_cast and const_cast, only static_cast is able to return an object of desirable type, whereas the other type can return only pointer or reference to representation. Why is it so?

Examples:

int y = 3;
double z = reinterpret_cast<double> (y);//error
double z = reinterpret_cast<double&> (y);//ok
double z = static_cast<double> (y);//but this is ok!!!

const int y = 3;
int z = const_cast<int> (y);//error
int z = const_cast<int&> (y);//ok

and for dynamic_cast:

using namespace std;

class Gun
{
public:
    virtual void shoot(){
        cout << "BANG!\n";
    }
};

class MachineGun : public Gun{
public:
    void shoot() override{
        cout <<"3X-BANG\n";
    }
};

int main()
{
    Gun gun;
    MachineGun tt;
    Gun* gunp = &gun;
    Gun* gunp1 = &tt;

    Gun* newGun = dynamic_cast<Gun*>(gunp1);//ok
    Gun newGun1 = dynamic_cast<Gun>(tt);//error
}
3

There are 3 best solutions below

1
Öö Tiib On BEST ANSWER

I'm making attempt to explain based on example, as addition to other answer that did explain nature of casts.

int y = 3;
double z = reinterpret_cast<double> (y);//error

This is not one of 11 allowed casts with reinterpret_cast. Also std::bit_cast can't cast it on most platforms as the int typically does not have enough bits for double. So it is unsure what you wanted to achieve.

double z = reinterpret_cast<double&> (y);//ok

This is present in list of valid reinterpret_cast but likely causes undefined behaviour for same reason why std::bit_cast refuses. In typical implementation your z is bigger than y and so takes bits beyond memory location of y. In such places prefer std::bit_cast that does not compile to undefined behaviour but refuses to compile.

double z = static_cast<double> (y);//but this is ok!!!

But that is fully valid. It is effectively same as

double z = y;

Compilers do not even warn about the latter. However when the value range of y does not fully fit to z then it is not clear if it was intentional. On such cases it is better to use former to indicate intent.

const int y = 3;
int z = const_cast<int> (y);//error

That is good. Absurd const_cast does not compile! Or how does the effect that you tried to achieve differ from lot more readable

int z = y;

I would write that. Please describe the situation where you would write former.

int z = const_cast<int&> (y);//ok

Works, but is similarly unneeded and confusing like previous. I would only use const_cast for situations like that:

int x;
const int& y = x;
int& z = const_cast<int&> (y);
z = 42;

Here I know that thing referred by reference to const y is really not const originally and so it is not undefined behaviour to modify it to 42.

About dynamic_cast your example does not make sense at all what it wants to do:

Gun newGun1 = dynamic_cast<Gun>(tt);//error

It could be perhaps trying to do something like that:

Gun newGun1 = tt;

That compiles. However that results with newGun1 initialised with sliced out Gun base sub-object of MachineGun tt and that is often programming error. What you tried to achieve with cast remains totally dark however.

8
eerorika On

Only static_cast is able to return an object of desirable type

This is incorrect. All casts return an object when the cast target is an object type.

That said:

  • const_cast target can only be a reference, pointer to object or pointer to member. This is because other types aren't compound types whose "inner" type's cv-qualifiers could be modified.
  • dynamic_cast target can only be a reference or a pointer to object. You cannot have polymorphism without indirection. References and pointers are the forms of indirection that exist in C++.
0
alfC On

Maybe a short (memorable) answer is that static_cast can take a type with no reference (and no pointer) because it is the only cast that can invoke a constructor of the target type.

Please correct me if I am wrong.