17
struct A{}; struct B : A{}; int main() { A a; A& a_ref = a; static_cast<B>(a); // *1 static_cast<B&>(a_ref); // *2 return 0; } 

(*1) produces an error and i understand why. (*2) compiles fine, but why? And, as long as it compiles and suppose B contains some attributes, what if i cast a_ref to B& and then try to access the attributes? I think i will have an run-time error or something.

So, as i can see, there is a situation which leads to crash and there are no ways to avoid it, unlike with dynamic_cast where one can check the result of casting for null or put code in a try-catch region. How do i have to deal with such situation where i need to cast references and be sure that i really get the right references.

7
  • You have to know what you're doing with static_cast, there are no runtime exceptions on wrongly used statically casted results. Commented Oct 30, 2013 at 13:06
  • 3
    You can use static_cast to downcast lvalues to references of derived classes, because there's no implicit cast for that way (as opposed to converting from a derived to a base class). You should only use it for that purpose if you know beforehand that it's safe (i.e. that the lvalue you're converting is of the derived type or derived). Commented Oct 30, 2013 at 13:08
  • Possible XY Problem. Why would you need a reference to the derived type? Commented Oct 30, 2013 at 13:08
  • @JohnDibling: I need it exactly for casting A& to B& and work with attributes. Commented Oct 30, 2013 at 13:15
  • A compiler will only find certain kinds of problems. Line *2 in isolation seems fine, since casting an A& to a B& would be valid in some situations. The compiler would have to do more sophisticated analysis to determine that it isn't actually valid in this case. This may be either too difficult or too slow to be practical. Commented Oct 30, 2013 at 13:16

5 Answers 5

10

From standard n3337 draft 5.2.9/2

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.

In your case:

B is class derived from A, both are non-const, and conversion from A* to B* is allowed, A is not virtual base class of D.

Sign up to request clarification or add additional context in comments.

Comments

6

This is one of the reasons why I use boost::polymorphic_downcast (doc) - in debug it uses dynamic_cast followed by assert and in release it is static_cast, so no performance hit.

1 Comment

thanks for the info, i'll check boost::polymorphic_downcast
6

static_cast<> will only check if the types are compatible

In case 1 types are not directly compatible since the re is no operator to describe the copy relation between A and B

In case 2 the cast is a reference cast and as far as the compiler is concerned A* can be casted to B* because they are compatible. The compiler will not know what the pointer a_ref holds so that's why it allows you to use it. dynamic_cast<> checks the class the pointer points to also.

Comments

2

(*2) compiles fine, but why?

In general, you can't check the dynamic type statically; and static_cast doesn't do any dynamic type checking. It allows any conversion that might be valid according to the static types, including conversions that aren't valid according to the dynamic types.

what if i cast a_ref to B& and then try to access the attributes?

Undefined behaviour. If you use static_cast, then the onus is on you to make sure the conversion is valid.

How do i have to deal with such situation where i need to cast references and be sure that i really get the right references.

For polymorphic types, use dynamic_cast. Applied to a reference, it will throw std::bad_cast if the conversion is not valid.

For non-polymorphic types, you're on your own.

Comments

0

It is important to highlight the point mentioned in dyp's comment, which is also hinted by Mike Seymour's answer.

Unlike dynamic_cast, static_cast doesn't perform any run-time check about the validity of the casting. If we are sure that a pointer (or reference) to a base class is pointing (or referring) to a derived object, static_cast can be safely used to cast it to a pointer (or reference) to the derived type. The attributes of the derived class will be available. In such safe settings, using static_cast leads to performance gains compared to using dynamic_cast.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.