Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <blockquote> <p>can you please elaborate following rules: </p> </blockquote> <p>I'll try:</p> <blockquote> <p>a) standard-layout classes must have all non-static data members with the same access control</p> </blockquote> <p>That's simple: all non-static data members must <em>all</em> be <code>public</code>, <code>private</code>, or <code>protected</code>. You can't have some <code>public</code> and some <code>private</code>.</p> <p>The reasoning for them goes to the reasoning for having a distinction between "standard layout" and "not standard layout" at all. Namely, to give the compiler the freedom to choose how to put things into memory. It's not just about vtable pointers.</p> <p>Back when they standardized C++ in 98, they had to basically predict how people would implement it. While they had quite a bit of implementation experience with various flavors of C++, they weren't certain about things. So they decided to be cautious: give the compilers as much freedom as possible.</p> <p>That's why the definition of POD in C++98 is so strict. It gave C++ compilers great latitude on member layout for most classes. Basically, POD types were intended to be special cases, something you specifically wrote for a reason.</p> <p>When C++11 was being worked on, they had a lot more experience with compilers. And they realized that... C++ compiler writers are really lazy. They had all this freedom, but they didn't <em>do</em> anything with it.</p> <p>The rules of standard layout are more or less codifying common practice: most compilers didn't really have to change much if anything at all to implement them (outside of maybe some stuff for the corresponding type traits).</p> <p>Now, when it came to <code>public</code>/<code>private</code>, things are different. The freedom to reorder which members are <code>public</code> vs. <code>private</code> actually can matter to the compiler, particularly in debugging builds. And since the point of standard layout is that there is compatibility with other languages, you can't have the layout be different in debug vs. release.</p> <p>Then there's the fact that it doesn't really hurt the user. If you're making an encapsulated class, odds are good that all of your data members will be <code>private</code> anyway. You generally don't expose public data members on fully encapsulated types. So this would only be a problem for those few users who do want to do that, who want that division.</p> <p>So it's no big loss.</p> <blockquote> <p>b) only one class in the whole inheritance tree can have non-static data members,</p> </blockquote> <p>The reason for this one comes back to why they standardized standard layout again: common practice.</p> <p>There's <em>no</em> common practice when it comes to having two members of an inheritance tree that actually store things. Some put the base class before the derived, others do it the other way. Which way do you order the members if they come from two base classes? And so on. Compilers diverge greatly on these questions.</p> <p>Also, thanks to the zero/one/infinity rule, once you say you can have two classes with members, you can say as many as you want. This requires adding a lot of layout rules for how to handle this. You have to say how multiple inheritance works, which classes put their data before other classes, etc. That's a lot of rules, for very little material gain.</p> <p>You can't make everything that doesn't have virtual functions and a default constructor standard layout.</p> <blockquote> <p>and the first non-static data member cannot be of a base class type (this could break aliasing rules).</p> </blockquote> <p>I can't really speak to this one. I'm not educated enough in C++'s aliasing rules to really understand it. But it has something to do with the fact that the base member will share the same address as the base class itself. That is:</p> <pre><code>struct Base {}; struct Derived : Base { Base b; }; Derived d; static_cast&lt;Base*&gt;(&amp;d) == &amp;d.b; </code></pre> <p>And that's probably against C++'s aliasing rules. In some way.</p> <p>However, consider this: how useful could having the ability to do this ever <em>actually</em> be? Since only one class can have non-static data members, then <code>Derived</code> must be that class (since it has a <code>Base</code> as a member). So <code>Base</code> <em>must</em> be empty (of data). And if <code>Base</code> is empty, <em>as well as</em> a base class... why have a data member of it at all?</p> <p>Since <code>Base</code> is empty, it has no state. So any non-static member functions will do what they do based on their parameters, not their <code>this</code> pointer.</p> <p>So again: no big loss.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload