Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!uunet!snorkelwacker!usc!rutgers!att!watmath!watmsg!gjditchfield From: gjditchfield@watmsg.uwaterloo.ca (Glen Ditchfield) Newsgroups: comp.std.c++ Subject: Packing Across Inheritance Boundaries is Currently Allowed. Message-ID: <1990Aug3.211414.23872@watmath.waterloo.edu> Date: 3 Aug 90 21:14:14 GMT Sender: daemon@watmath.waterloo.edu (Owner of Many System Processes) Distribution: comp Organization: University of Waterloo Lines: 61 I think that packing of classes is allowed by the current definition of C++. I base this conclusion on Ellis & Stroustrup's ``The Annotated C++ Reference Manual'', including the commentary sections, which may not be part of the proposed standard but which give information about its intent. The main discussion of the order of members is in section 9.2 ``Class Members'' on page 173. Nonstatic data members of a class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is implementation dependent (s. 11.1). Implementation alignment requirements may cause two adjacent members not to be allocated immediately after each other; so may requirements for managing virtual functions (s. 10.2) and virtual base classes (s. 10.1). Commentary in section 11.1 (p. 242) shows that a compiler might want to move all public members to the front of a class as part of a strategy to minimize recompilation. Section 10.1c is commentary, and says on page 218 that ``C++ does not guarantee the order in which storage is allocated for derived classes''. I couldn't find an explicit statement of this in non-commentary text. Apparently the members of a descendant class are considered to be separated from members in its parents by the (explicit or default) access-specifier in the derived class header. The commentary shows three ways that a derived class might be laid out. A compiler could take advantage of this to pack classes across inheritance boundaries. There is no guarantee that the addresses of all descendant class members are greater than the address of all base class members, so descendant members can be positioned in holes in the base class. If ``class Adam {char a1; long a2;}'' is laid out as .----v----v----v----v----v----v----v----. | a1 | hole | a2 | `----^----^----^----^----^----^----^----' then ``class Bob:public Adam {char a1;}'' can be laid out as .----v----v----v----v----v----v----v----. | a1 | b1 | hole | a2 | `----^----^----^----^----^----^----^----' if the compiler feels up to the task. A trickier question is whether the compiler is allowed to separate members with the same access-specifier in order to fill holes. For example, can ``class Chuck: public Bob { char c1, c2; short c3}'' be laid out this way? .----v----v----v----v----v----v----v----v----v----. | a1 | b1 | c1 | c2 | a2 | c3 | `----^----^----^----^----^----^----^----^----^----' I think that this is allowed. One might argue that is is forbidden, because c2 and c3 are not adjacent, and the separation is not caused by alignment requirements, virtual functions, or virtual base classes. However, I think that the list of reasons for separation in section 9.2 is not meant to be an exhaustive list. If it were, it would build assumptions about the implementation of inheritance into the language. Besides, such a restriction wouldn't help programmers much, since 9.2 already gives implementations permission to insert arbitrary separations between consecutive members if the class uses virtual functions or virtual base classes. Glen Ditchfield gjditchfield@violet.uwaterloo.ca Office: DC 2517 Dept. of Computer Science, U of Waterloo, Waterloo, Ontario, Canada, N2L 3G1 These opinions have not been tested on animals.