Unions aren't just for saving memory. They also allow
polymorphism in overlay form. For example, a network packet laid out in RAM might use different parts of the union depending on the packet type.
As for C++ and structs, you had to be there.
When Bjarne Stroustrup invented "C with classes" at AT&T Bell Labs, he wasn't inventing a language from scratch. Instead, he did like more than one earlier language designer did and implemented it as a pre-processor to convert his enhanced C into traditional C so that he could use the Unix C compiler to actually do the heavy lifting (just as early Unix C compilers translated C to assembly to let the assembler do the grunt work).
So to build the concepts of C++ classes, he started out by enhancing structs. In fact, a struct and a class have the same semantics, except that a struct has an implicit default member visibility of public and a class has an implicit default member visibility of private. If my rotting memory fails me not, you can even "subclass" structs - or at least could on the original language implements.
One of the key differences between C/C++ and
Java is that a Java class is a
data structure, but a C struct/class is a
storage structure. Both are ordered collections of heterogeneous data, but a storage structure has a direct calculable mapping to specific areas of memory (relative to the object base), but a data structure is only a logical construct, not a physical one and the locations of its elements in memory are not meant to be predictable.