Suppose I have a union and I know the active member derives from some (non-standard layout) base class, but I don't know which specific member is active. Is it legal to cast a pointer to that union, via void *
, to a pointer to the base class, then use that base pointer?
For example, is this (which does compile with g 11.3.0
with -std=c 23
) legitimate?
class base { public: virtual bool foo() = 0; };
class derived_1 : public base { bool foo() override { return true; }; };
class derived_2 : public base { bool foo() override { return false; }; };
union some_base {
derived_1 x;
derived_2 y;
bool foo() {
return static_cast<base *>(static_cast<void *>(this))->foo();
};
};
CodePudding user response:
The union object that this
points to is pointer-interconvertible with the active derived_1
or derived_2
, but it is not pointer-interconvertible with the base class subobject of either. Pointer-interconvertibility between base and derived classes applies only to standard layout classes.
Therefore the cast will not result in a pointer to the base class subobject and the member access will have undefined behavior as the actual type of the pointed-to object is not similar to that of the expression.
The layout of the classes is not relevant to this. It is more similar to an aliasing violation. However, even regarding layout, there is nothing requiring the implementation to place the Base
subobject at zero offset (or at equal offsets at all) into derived_1
and derived_2
.
The ABI specification will make a determination regarding the last point though. Then assuming that the layout is appropriate, it may very well work in practice. I am not sure whether or to what degree compilers use this aliasing-type violation for optimization in practice.