類型別

class 是指使用 classstruct 關鍵字定義的型別(但不是 enum structenum class)。

  • 即使是空類仍然佔用至少一個位元組的儲存空間; 因此它將純粹由填充物組成。這確保瞭如果 p 指向空類的物件,則 p + 1 是一個不同的地址並指向一個不同的物件。但是,當用作基類時,空類的大小可能為 0。檢視空基優化

    class Empty_1 {};                               // sizeof(Empty_1)       == 1
    class Empty_2 {};                               // sizeof(Empty_2)       == 1
    class Derived : Empty_1 {};                     // sizeof(Derived)       == 1
    class DoubleDerived : Empty_1, Empty_2 {};      // sizeof(DoubleDerived) == 1
    class Holder { Empty_1 e; };                    // sizeof(Holder)        == 1
    class DoubleHolder { Empty_1 e1; Empty_2 e2; }; // sizeof(DoubleHolder)  == 2
    class DerivedHolder : Empty_1 { Empty_1 e; };   // sizeof(DerivedHolder) == 2
    
  • 類型別的物件表示包含基類的物件表示和非靜態成員型別。因此,例如,在以下類中:

    struct S {
        int x;
        char* y;
    };
    

    S 物件中有一個連續的 sizeof(int) 位元組序列,稱為*子物件,*包含 x 的值,另一個子物件的 sizeof(char*) 位元組包含 y 的值。兩者不能交錯。

  • 如果類型別具有型別為 t1, t2,...tN 的成員和/或基類,則在給定前面的點的情況下,大小必須至少為 sizeof(t1) + sizeof(t2) + ... + sizeof(tN)。但是,根據成員和基類的對齊要求,可能會強制編譯器在子物件之間或整個物件的開頭或結尾插入填充。

    struct AnInt      { int i; };
      // sizeof(AnInt)        == sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(AnInt)        == 4 (4).
    struct TwoInts    { int i, j; };
      // sizeof(TwoInts)      >= 2 * sizeof(int)
      // Assuming a typical 32- or 64-bit system, sizeof(TwoInts)      == 8 (4 + 4).
    struct IntAndChar { int i; char c; };
      // sizeof(IntAndChar)   >= sizeof(int) + sizeof(char)
      // Assuming a typical 32- or 64-bit system, sizeof(IntAndChar)   == 8 (4 + 1 + padding).
    struct AnIntDerived : AnInt { long long l; };
      // sizeof(AnIntDerived) >= sizeof(AnInt) + sizeof(long long)
      // Assuming a typical 32- or 64-bit system, sizeof(AnIntDerived) == 16 (4 + padding + 8).
    
  • 如果由於對齊要求而在物件中插入填充,則大小將大於成員和基類的大小之和。對於 n 位元組對齊,大小通常是 n 的最小倍數,它大於所有成員和基類的大小。每個成員 memN 通常會被放置在一個地址上,該地址是 alignof(memN) 的倍數,而 n 通常是所有成員的 alignof 中最大的 alignof。因此,如果具有較小 alignof 的構件後面跟著具有較大 alignof 的構件,則如果緊接在前者之後放置後者,則後者可能不會正確對齊。在這種情況下,填充(也稱為對齊構件 )將被放置在兩個構件之間,使得後者可以具有其期望的對準。相反,如果具有較大 alignof 的成員後跟一個具有較小 alignof 的成員,則通常不需要填充。這個過程也稱為包裝
    由於類通常與最大的會員共享其會員的節目,因此類通常與他們直接或間接包含的最大內建型別的節目 27 對齊。

    // Assume sizeof(short) == 2, sizeof(int) == 4, and sizeof(long long) == 8.
    // Assume 4-byte alignment is specified to the compiler.
    struct Char { char c; };
      // sizeof(Char)                == 1 (sizeof(char))
    struct Int  { int i; };
      // sizeof(Int)                 == 4 (sizeof(int))
    struct CharInt { char c; int i; };
      // sizeof(CharInt)             == 8 (1 (char) + 3 (padding) + 4 (int))
    struct ShortIntCharInt { short s; int i; char c; int j; };
      // sizeof(ShortIntCharInt)     == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    3 (padding) + 4 (int))
    struct ShortIntCharCharInt { short s; int i; char c; char d; int j; };
      // sizeof(ShortIntCharCharInt) == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) +
      //                                    1 (char) + 2 (padding) + 4 (int))
    struct ShortCharShortInt { short s; char c; short t; int i; };
      // sizeof(ShortCharShortInt)   == 12 (2 (short) + 1 (char) + 1 (padding) + 2 (short) +
      //                                    2 (padding) + 4 (int))
    struct IntLLInt { int i; long long l; int j; };
      // sizeof(IntLLInt)            == 16 (4 (int) + 8 (long long) + 4 (int))
      // If packing isn't explicitly specified, most compilers will pack this as
      //   8-byte alignment, such that:
      // sizeof(IntLLInt)            == 24 (4 (int) + 4 (padding) + 8 (long long) +
      //                                    4 (int) + 4 (padding))
    
    // Assume sizeof(bool) == 1, sizeof(ShortIntCharInt) == 16, and sizeof(IntLLInt) == 24.
    // Assume default alignment: alignof(ShortIntCharInt) == 4, alignof(IntLLInt) == 8.
    struct ShortChar3ArrShortInt {
        short s;
        char c3[3];
        short t;
        int i;
    };
      // ShortChar3ArrShortInt has 4-byte alignment: alignof(int) >= alignof(char) &&
      //                                             alignof(int) >= alignof(short)
      // sizeof(ShortChar3ArrShortInt) == 12 (2 (short) + 3 (char[3]) + 1 (padding) +
      //                                      2 (short) + 4 (int))
      // Note that t is placed at alignment of 2, not 4.  alignof(short) == 2.
    
    struct Large_1 {
        ShortIntCharInt sici;
        bool b;
        ShortIntCharInt tjdj;
    };
      // Large_1 has 4-byte alignment.
        // alignof(ShortIntCharInt) == alignof(int) == 4
        // alignof(b) == 1
        // Therefore, alignof(Large_1) == 4.
      // sizeof(Large_1) == 36 (16 (ShortIntCharInt) + 1 (bool) + 3 (padding) +
      //                        16 (ShortIntCharInt))
    struct Large_2 {
        IntLLInt illi;
        float f;
        IntLLInt jmmj;
    };
      // Large_2 has 8-byte alignment.
        // alignof(IntLLInt) == alignof(long long) == 8
        // alignof(float) == 4
        // Therefore, alignof(Large_2) == 8.
      // sizeof(Large_2) == 56 (24 (IntLLInt) + 4 (float) + 4 (padding) + 24 (IntLLInt))
    

Version >= C++ 11

  • 如果使用 alignas 強制進行嚴格對齊,則將使用填充來強制型別滿足指定的對齊,即使它會更小。例如,使用下面的定義,Chars<5> 將在末尾插入三個(或可能更多)填充位元組,以使其總大小為 8.對於 4 的對齊的類不可能具有 5 的大小,因為製作該類的陣列是不可能的,因此必須通過插入填充位元組將大小四捨五入到 4 的倍數。

    // This type shall always be aligned to a multiple of 4.  Padding shall be inserted as
    // needed.
    // Chars<1>..Chars<4> are 4 bytes, Chars<5>..Chars<8> are 8 bytes, etc.
    template<size_t SZ>
    struct alignas(4) Chars { char arr[SZ]; };
    
    static_assert(sizeof(Chars<1>) == sizeof(Chars<4>), "Alignment is strict.\n");
    
  • 如果一個類的兩個非靜態成員具有相同的訪問說明符 ,那麼稍後在宣告順序中出現的那個成員將保證稍後在物件表示中出現。但是,如果兩個非靜態成員具有不同的訪問說明符,則它們在物件中的相對順序是未指定的。

  • 未指定基類子物件在物件中出現的順序,是否它們是連續出現的,以及它們是出現在成員子物件之前,之後還是之間。