开发者

Downcasting a base type

In C++, is it Undefined Behavior if a Base class object is instantiated as a base object, and subsequently downcast to a derived object?

Of course, I would assume it definitely must be undefined behavior, because the Derived class object might have member variables which the base class doesn't. So these variables wouldn't actually exist if the class was instantiated as a base object, which means that accessing them through a Derived class pointer would have to cause Undefined Behavior.

But, what if the Derived class simply provides extra member functions, but doesn开发者_StackOverflow社区't include any further member data? For example:

class Base
{
    public:
    int x;
};

class Derived : public Base
{
    public:
    void foo();    
};

int main()
{
    Base b;
    Derived* d = static_cast<Derived*>(&b);
    d->foo(); // <--- Is this undefined behavior?
}

Does this program cause undefined behavior?


Yes, it's still undefined behavior, because you're lying to the compiler about the real type of d.

See the standard 5.2.9/8:

An rvalue of type “pointer to cv1 B”, where B is a class type, can be converted to an rvalue of type “pointer to cv2 D”, where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cvqualification as, or greater cvqualification than, cv1, and B is not a virtual base class of D. The null pointer value (4.10) is converted to the null pointer value of the destination type. If the rvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

The final two sentences say that if the B pointed to by the pointer is not actually part of a D derived class, the cast is undefined behavior.


The C++03 standard, par. 5.2.9.8 lays it out (emphasis mine):

An rvalue of type “pointer to cv1 B”, where B is a class type, can be converted to an rvalue of type “pointer to cv2 D”, where D is a class derived (clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. The null pointer value (4.10) is converted to the null pointer value of the destination type. If the rvalue of type “pointer to cv1 B” points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.


Yes, that is completely undefined behaviour. That's why when downcasting you should favour dynamic_cast unless you're very very sure.


Given the mental model I have of C++ implementation in terms of generated machine code I'd say that if the method called is not virtual and the derived class is not introducing virtual methods when the base class has none, and multiple inheritance is not involved in this trickery and and and ... it should work as you expect if the method code is indeed only accessing members defined in base object.

However this is still clearly UB in C++.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜