Object layout
Chapter 4 stated that a struct
written for a C compiler and later compiled with C++ would be unchanged. This
referred primarily to the object layout of the struct, that is, where the
storage for the individual variables is positioned in the memory allocated for
the object. If the C++ compiler changed the layout
of C
structs, then any C code you wrote that inadvisably took advantage of
knowledge of the positions of variables in the struct would
break.
When you start using access specifiers,
however, you’ve moved completely into the C++ realm, and things change a
bit. Within a particular “access block” (a
group of declarations delimited by access specifiers), the variables are
guaranteed to be laid out contiguously, as in C. However, the access blocks may
not appear in the object in the order that you declare them. Although the
compiler will usually lay the blocks out exactly as you see them, there
is no rule about it, because a particular machine architecture and/or operating
environment may have explicit support for
private and
protected that might
require those blocks to be placed in special memory locations. The language
specification doesn’t want to restrict this kind of
advantage.
Access specifiers are part of the
structure and don’t affect the objects created from the structure. All of
the access specification information disappears before the program is run;
generally this happens during compilation. In a running program, objects become
“regions of storage” and nothing more. If you really want to, you
can break all the rules and access the memory directly, as you can in C. C++ is
not designed to prevent you from doing unwise things. It just provides you with
a much easier, highly desirable alternative.
In general, it’s not a good idea to
depend on anything that’s implementation-specific when you’re
writing a program. When you must have implementation-specific dependencies,
encapsulate them inside a structure so that any porting changes are focused in
one
place.