Why this code is valid in C++:
class Base
{
public:
Base() = default;
// base class stuff...
};
template<typename NumericType>
class Numeric : public Base
{
public:
Numeric() : m_value() {}
void setValue(NumericType value) { m_value = value; }
NumericType value() const { return m_value; }
private:
NumericType m_value;
};
int main()
{
auto integerPtr = new Numeric<int>();
Base *basePtr = integerPtr;
if (auto doublePtr = static_cast<Numeric<double>*>(basePtr)) {
doublePtr->setValue(6543423.634234);
std::cout << "Wow: " << doublePtr->value() << std::endl;
}
return 0;
}
Compiler: MCVS2019 32bit.
Edit: my fault, totally forgot about static_cast
and dynamic_cast
nuances. Code is make sense, but is illformed.
See static_cast
from cppreference:
- If new_type is a reference or pointer to some class D and expression is lvalue of its non-virtual base B or prvalue pointer to it, static_cast performs a downcast. (This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D.) Such a downcast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.
Your code invokes undefined behavior, because the cast is ill-formed. You should use dynamic_cast
for up/downcasts. Provide a virtual destructor in Base
then this code:
#include <iostream>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
};
template<typename NumericType>
class Numeric : public Base
{
public:
Numeric() : m_value() {}
void setValue(NumericType value) { m_value = value; }
NumericType value() const { return m_value; }
private:
NumericType m_value;
};
int main()
{
auto integerPtr = new Numeric<int>();
Base *basePtr = integerPtr;
if (auto doublePtr = dynamic_cast<Numeric<double>*>(basePtr)) {
doublePtr->setValue(6543423.634234);
std::cout << "Wow: " << doublePtr->value() << std::endl;
}
return 0;
}
Is correct and produces no output as expected.
Why this code is valid in C++
It is not valid code. Remember that incorrect code does not necessarily produce compiler errors. Anything can happen when your code has undefined behavior.
PS: I would have expected your code to blow up when optimizations are turned on. To my surprise, it still appears to work (https://godbolt.org/z/czfobbfqo). Thats the nasty side of undefined behavior. It may go unnoticed and will only blow up once you shipped the code and make a demo in front of your customers ;).