c++dynamic-castreinterpret-caststatic-castconst-cast

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


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
}

Solution

  • 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.