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.