2

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:

  • 1) what casting is the compiler doing? I'm assuming a reinterpret_cast maybe?
  • 2) would static_cast< Derived& >(b) work as well?
  • 3) if class Derived added some methods/attributes (not used in foo), would this still work?
  • 4) is the key point that foo does not use any functionality of Derived that is not already in Base?

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

bartgol
  • 1,703
  • 2
  • 20
  • 30
  • 2
    Whoever used inheritance solely to fix an attribute with a value doesn't understand OOP or C++... – StoryTeller - Unslander Monica Mar 20 '13 at 16:43
  • See here for casting descriptions - http://stackoverflow.com/a/332086/2065121 – Roger Rowland Mar 20 '13 at 16:43
  • @StoryTeller: I totally agree with you. This child class (which except construction time, works EXACTLY the same as the parent) is creating a lot of problems. Btw, this is from the Trilinos library. I asked a while ago the reason for that but my mail never got an answer. Whatever. – bartgol Mar 29 '13 at 14:54

1 Answers1

1

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&.
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324