2

Motivating background: While trying to debug a hard-to-reproduce fault-condition in my software, I came across some questionable pointer-casting code that was written by a naive junior developer (okay, I admit it, it was me, 10 years ago) that I suspect might be the underlying cause of the fault.

I rewrote the code to use proper static_cast<> calls instead, and I haven't seen the fault condition occur since the rewrite, but that doesn't necessarily mean anything given that the fault rarely occurred anyway; I could just be "getting lucky" so far.

My question is: does the C-style up-casting of pointers performed inside main() in the code below invoke undefined behavior? Or is it just ugly, but nevertheless well-formed from a language-lawyer perspective?

#include <stdio.h>
#include <stdlib.h>

class BaseClass
{
public:
   BaseClass() {}
   virtual ~BaseClass() {}

   virtual void Foo() {printf("BaseClass::Foo() called\n");}
};

class SubClassA : public BaseClass
{
public:
   SubClassA() {}

   virtual void Foo() {printf("SubClassA::Foo() called\n");}
};

class SubClassB : public BaseClass
{
public:
   SubClassB() {}

   virtual void Foo() {printf("SubClassB::Foo() called\n");}
};

int main(int, char **)
{
   SubClassA a;
   SubClassB b;

   // Warning:  questionable C-style casting follows...
   BaseClass * p = (rand()%2) ? ((BaseClass*)(&a)) : ((BaseClass*)(&b));
   p->Foo();

   return 0;
}
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • If the ternary operator in combination with any casting gives any kind of undesirable result, I bet a nice dinner (restaurant is my pick) that at the core of the problem is NOT the ternary operator. It is always the casting (or something you missed altogether). – Yunnosch Jul 31 '20 at 16:19
  • If the C-style upcasting is legal to begin with, I can't see a reason why it would become undefined when put into the conditional operator. – Barmar Jul 31 '20 at 16:19
  • 2
    The type of a conditional operator only becomes confusing when the true and false subexpressions are different types -- a common type has to be determined for the whole expression. But that's not an issue here. – Barmar Jul 31 '20 at 16:21

1 Answers1

3

The cast is completely legal. From [expr.cast]/4.6

a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicitly converted to a pointer or reference to an unambiguous base class type, respectively;

NathanOliver
  • 171,901
  • 28
  • 288
  • 402