Search code examples
c++inheritanceaccess-specifier

Is size of the object affected by type of access-specifier and type of inheritance?


While answering one of the question, there was a discussion thread below my answer. Which suggests that depending on the access specifier (or may be the type of inheritance) private/protected/public the sizeof the class object may vary!

I still don't understand from their brief discussion, how is that possible ?


Solution

  • Note new language for C++11 below

    In C++03, there is language that makes this possible, 9.2 [class.mem]/12 (emphasis mine):

    Nonstatic data members of a (non-union) 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 unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

    So given this definition:

    class Foo
    {
        char a; //8 bits
        // a must come before b, so 3 bytes of padding have to go here to satisfy alignment
        int b; //32 bits
        char c; //8 bits
        // 24 bits of padding required to make Foo a multiple of sizeof(int)
    };
    

    on a system with 32 bit (int) alignment, the compiler is not allowed to reorder c to come before b, forcing the insertion of additional padding padding in between a and b, and after c to the end of the object (making sizeof(Foo) == 12). However, for this:

    class Foo
    {
        char a;
    public:
        int b;
    public:
        char c;
    };
    

    a and (b and c) are separated by an access specifier, so the compiler is free to perform such reordering, making

    memory-layout Foo
    {
        char a; // 8 bits
        char c; // 8 bits
        // 16 bits of padding
        int b; // 32 bits
    };
    

    sizeof(Foo) == 8.

    In C++11, the language changes slightly. N3485 9.2 [class.mem]/13 says (emphasis mine):

    Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

    This means that in C++11, in the above example (separated by 3 publics), the compiler is still not allowed to perform the reordering. It would have to be something like

    class Foo
    {
        char a;
    public:
        int b;
    protected:
        char c;
    };
    

    , which places a, b, and c with different access control.

    Note that under the C++11 rules, given a definition like:

    class Foo
    {
        char a;
    public:
        int b;
    protected:
        char c;
    public:
        int d;
    };
    

    the compiler must put d after b, even though they are separated by access specifiers.


    (That said, I'm not aware of any implementation that actually takes advantage of the latitude offered by either standard)