Home > Enterprise >  Using a static_cast on non-pointer related types
Using a static_cast on non-pointer related types

Time:06-08

I discover this compiler trick and I cannot find a name for. Have you any idea?
On an Intel processor, I can cast a variable from its base class to an inherited class. It works with MSVC, gcc and clang and I am very confused.

#include <string>
#include <iostream>

class A
{
public:
    virtual std::string print() const { return "A"; }
};

class B : public A
{
public:
    std::string print() const override { return "B"; }
    std::string printOther() const { return "other"; }
};

int main()
{
    A a;

    std::cout << a.print() << std::endl; // print A

    std::cout << static_cast<const B&>(a).print() << std::endl; // print A
    std::cout << static_cast<const B&>(a).B::print() << std::endl; // print B
    std::cout << static_cast<const B&>(a).printOther() << std::endl; // print other

    try
    {
        std::cout << dynamic_cast<const B&>(a).printOther() << std::endl; // throw std::bad_cast
    }
    catch (const std::bad_cast& e)
    {
        std::cout << e.what() << std::endl; // print std::bad_cast
    }

    std::cout << ((const B&)a).print() << std::endl; // print A
    std::cout << ((const B&)a).B::print() << std::endl; // print B
    std::cout << ((const B&)a).printOther() << std::endl; // print other

    std::cout << reinterpret_cast<const B&>(a).print() << std::endl; // print A
    std::cout << reinterpret_cast<const B&>(a).B::print() << std::endl; // print B
    std::cout << reinterpret_cast<const B&>(a).printOther() << std::endl; // print other

    // error: invalid 'const_cast' from type 'A*' to type 'const B*'
    //std::cout << const_cast<const B&>(a).print() << std::endl; // print A
    //std::cout << const_cast<const B&>(a).printOther() << std::endl; // print other

    return 0;
}

CodePudding user response:

Yes, static_cast can cast a class to a reference to a derived class. That is not a trick or compiler-specific. That is one of the specified purposes of static_cast in the C standard.

However, this cast has undefined behavior if the object isn't actually a base subobject of a derived class object.

In your case here you never created a B object, only a A object. Therefore all of the static_cast have undefined behavior and your program is broken.


(const B&)a effectively is defined to do the same as static_cast<const B&>(a) if the type B is a derived class type of the type of a. So all of them in your code also have undefined behavior and are broken.


dynamic_cast<const B&>(a) is allowed here since your class is polymorphic (has a virtual member function). It will work correctly and fail with an exception if a isn't actually a base subobject of a B object rather than causing undefined behavior.

dynamic_cast is the only cast that you may use if you are not sure that a actually is a base subobject of a B.


reinterpret_cast<const B&>(a) does something completely different than the above and also causes undefined behavior, because your classes are not standard layout and therefore definitively not pointer-interconvertible.

  • Related