TITLE: Type casting in C versus C++


PROBLEM: ik@snoopy.ctt.bellcore.com (Ik Su Yoo)

I'm using cfront 2.1 with ObjectCenter 1.1 and having problem with the
following code:  [ condensed ]

    class A {
    public:
      virtual void f();
    };

    class B: public virtual A { };

    B bb;
    void* bbp = &bb;
    ((B*)bbp)->f();
    ((A*)bbp)->f();


RESPONSE: steve@taumet.com (Steve Clamage)


Pointer casts in C++ do not in general mean "copy the bits".  When a
class hierarchy is involved, the compile-time type is taken into
account to adjust the pointer value.  When you cast &bb to type void*,
you lose all the compile-time type information.

For example, when a B* is cast to an A*, there is a value change.
The A base class does not start at the same address as the B derived
class -- a virtual base must be located somewhere else.  The compiler
generates code to adjust the address to the start of the A object.

In your example, you take the address of a B, cast it to void*.  Then
you take the void* and cast it to type A*.  The information that the
address is really of a B was lost to the compiler, so it can't make the
adjustment.  You take the address of the B and try to use it as though
it were the address of an A, which it is not.


[ You can always cast a pointer from T* to void* then back to T*
  without any problems. Casting becomes more problematic in the
  presence of multiple inheritance. -adc ]


RESPONSE: mat@uunet.uu.net!mole-end (Mark Terribile)

Casting of pointers in C is pure `bitblt.'  In C++, it can imply conversion.


RESPONSE: steve@taumet.com (Steve Clamage)

Actually, casting of pointers in C can also involve conversion.  To
take a homely example, casting a near to a far pointer (or the reverse)
on Intel architectures certainly involves conversion, since they are
not the same size.  There are machines where pointers to some types
(especially char*) are different sizes, or have different formats, than
pointers to other types.

For these reasons, the C Standard is careful to say that casting
among different pointers is not guaranteed to work, and that a
conversion is in general involved.  The result of a cast is a value,
not an lvalue.  (Some compilers allow casts to be treated as lvalues
under some poorly-defined circumstances.)  This characterization of
pointer casts was not an invention of the ANSI C committee, by the
way, but appears in K&R1.
