bartgol
bartgol

Reputation: 1873

Casting down the hierarchy a concrete object

I am looking at a piece of code where there's a c-style cast that puzzles me.

I am fairly familiar with casting, but this one I really can't grasp. So, here it is: I have two classes, say Base and Derived, but Derived does not add any method/attribute. Basically it's just a particular case of Base when one of its attributes (call it M_blockSize) is fixed to 1; however, none of the methods requires a particular implementation nor there is an extension of functionalities. The benefit of such Derived class is not the point of this thread. Let's assume the developers had their good reasons for this.

Anyway, in the piece of code I'm looking something like this happens:

void foo(const Derived& d){...}
[...]
Base b;
foo((Derived&) b);

So, the developers casted the base object into a reference to a derived one. In my understanding, downcasting is done if the concrete type of the "castee" (b) is indeed Derived. Which is not the case here.

However, this is c-style cast, so the compiler is trying a whole bunch of casts and I don't know which one it eventually works.

So, questions:

I hope the question is clear. Thank you for your help.

Upvotes: 2

Views: 1049

Answers (1)

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

The cast in effect here is a static_cast<Derived&>, governed by the following rule (§5.2.9 Static cast):

An lvalue of type "cv1 B," where B is a class type, can be cast to type "reference 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 neither a virtual base class of D nor a base class of a virtual base class of D. The result has type "cv2 D."

The cast "pointer to D" to "pointer to B" is a valid standard conversion (§4.10):

A prvalue of type "pointer to cv D", where D is a class type, can be converted to a prvalue of type "pointer to cv B", where B is a base class (Clause 10) of D.

However, just because the cast works, doesn't mean it's okay to do. Note (§5.2.9):

If the object of type "cv1 B" is actually a subobject of an object of type D, the result refers to the enclosing object of type D. Otherwise, the result of the cast is undefined.

So this code results in undefined behaviour. You can cast from a base class to any of its derived classes, but you only have define behaviour if it truly is an object of that derived type.

So to answer the questions:

  1. It's a static_cast<Derived&>.
  2. Yes, because that's what's happening.
  3. It doesn't work anyway because it results in undefined behaviour.
  4. I can't be certain what the point was here. I'd expect that it might continue to perform as expected if you don't use any Derived specific features inside foo. However, if that's the case, just take a Base&.

Upvotes: 1

Related Questions