c++ - Privacy property of inherited members affects overall size of class? - Stack Overflow

admin2025-04-29  2

Running this code below, the sizeof base class and derived class are both 32.

  #include "iostream"
  #include "string"

  using namespace std;

  class base{
  //public:
      int a;
      double b;
      void * c;
      char d;
  };

  class c1 :  base{
  //public:
      int a;
  };

  int main() {
      cout << sizeof(base) << endl;
      cout << sizeof(c1) << endl;
      return 0;
  }

However, if you undo the comment of keyword public:, sizeof derived class becomes 40.

I am totally lost here, why member variable being private or not affect the overall size?

Reproducible in GCC.

Running this code below, the sizeof base class and derived class are both 32.

  #include "iostream"
  #include "string"

  using namespace std;

  class base{
  //public:
      int a;
      double b;
      void * c;
      char d;
  };

  class c1 :  base{
  //public:
      int a;
  };

  int main() {
      cout << sizeof(base) << endl;
      cout << sizeof(c1) << endl;
      return 0;
  }

However, if you undo the comment of keyword public:, sizeof derived class becomes 40.

I am totally lost here, why member variable being private or not affect the overall size?

Reproducible in GCC.

Share Improve this question edited Jan 8 at 4:10 PkDrew asked Jan 8 at 3:48 PkDrewPkDrew 1,1002 gold badges7 silver badges23 bronze badges 8
  • 1 If I am remembering correctly I believe that this is from the Itianium ABI and when and how it allows the use of tail padding from base classes. You might find something searching for that – NathanOliver Commented Jan 8 at 3:50
  • 1 I found this, looks promising: stackoverflow.com/questions/61548135/… – NathanOliver Commented Jan 8 at 3:53
  • 1 This is up to the compiler, the same class can either have or not having the tail padding used if you change the compiler, on some compilers inheritance is enough, while others require visibility changes, etc ... it is allowed but not mandated so all those different behaviors are allowed. – Ahmed AEK Commented Jan 8 at 7:30
  • 1 Side note: nothing in this code needs the extra stuff that std::endl does. Use '\n' to end a line unless you have a good reason not to. – Pete Becker Commented Jan 8 at 13:18
  • 1 @PkDrew — yup. Flushes should be reserved for situations where they’re needed. – Pete Becker Commented Jan 9 at 2:43
 |  Show 3 more comments

1 Answer 1

Reset to default 3 +50

If you were using Clang, you may add -Xclang -fdump-record-layouts to get a look at actual layout compiler makes for you.

If you make member variables in base class public, you get the layout shown as below:

*** Dumping AST Record Layout
         0 | class base
         0 |   int a
         8 |   double b
        16 |   void * c
        24 |   char d
           | [sizeof=32, dsize=32, align=8,
           |  nvsize=32, nvalign=8]

As you can see the dsize and nvsize both have already taken 32 bytes. There is no room for merge of int a from derived class, namely c1 in your code.

The justification of compiler comes down to this ABI specification:

If C is a POD, but not a POD for the purpose of layout, set dsize(C) = nvsize(C) = sizeof(C).

A funny enough fact is, by adding a dummy constructor in your base class, sizeof(base) will be 32, because you effectively made your base a non-POD one, compiler is free to apply all sort of optimizations now.

转载请注明原文地址:http://anycun.com/QandA/1745882828a91305.html