I try to simulate C++\'s polymorphism in C with following code:
#include
typedef struct Base {
void (*out) (void);
} Base;
typedef struct Deri
Incompatible pointer assignment is not necessary. Per C 2011 [draft N1570] 6.7.2.1 15, “A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.” Thus, when the first element of Derived
is a Base
object, a pointer to Derived
may be converted to a pointer to a Base
. And a pointer to a Base
that is the first member in a Derived
may be converted to a pointer to Derived
.
So this is legal. The compiler is likely warning you about it just to be safe, since it is unusual. Using an explicit cast may avoid that:
p = (Base *) &d;
Alternatively, you can take the address of the base directly:
p = &d.base;
However, going from a Base back to a Derived will still require a cast:
Derived *x = (Derived *) p;
As for putting the base somewhere other than as the first member, then you are on shakier ground. The derived-to-base direction is still easy; p = &d.base
is fine. To go the other way, this may be as close as you can get to legal C:
Get a character-type pointer to the base: char *c = (char *) p
. In C, it is legal to convert any pointer to an object to a pointer to a character type, and this gives you a pointer to the first byte of the object.
Subtract the number of bytes from the beginning of a Derived
to the Base
member: c -= offsetof(Derived, base)
. (This requires including <stddef.h>
.) Since c
points to the first byte of a Base
in Derived
, it points to a byte in Derived
, and you are mostly (see below) allowed to treat Derived
as an array of bytes, so we can subtract to get back to the beginning. The offsetof
macro provides the number of bytes for that.
Convert the character-pointer to a pointer to Derived
: Derived *x = (Derived *) c
. Here, we are on shaky ground. If we converted a pointer to Derived
to a character pointer, we are allowed to convert it back immediately. But we did not get this pointer in that way. It points to the same byte, but it is not clear to me that the C standard supports this. (Actually, step 2 above has a similar problem; an object can be interpreted as an array of characters, but we are coming at it from a direction that I am not sure is actually supported by the C standard.)
Putting these together, the conversion would be:
Derived *x = (Derived *) ((char *) p - offsetof(Derived, base));
Given the uncertainties in support, I would use this only in experimental code or as a classroom exercise, unless I had guarantees from the C implementation I was using that this pointer arithmetic is supported. It would be preferable to stick with the base as the first element, as those conversions are strictly conforming C.