This is something I do that I am sure will drive some people nuts.
The software engineering field is full of people who get driven nuts by small things that make little difference. Many of those people join the "coding style" committees of their respective work places, and then turn their own preferences into the law. Enforcement of these preferences then leads to a culture of rigid code reviews, lots of effort being put into checker and formatter tools, people looking at style rather than substance. Instead of writing good software (bug free, easy to understand and therefore fix and enhance in the future) they write software that matches the coding rules perfectly. The whole thing becomes a culture of "virtue signaling" instead of doing the right thing.
In C++, struct and class are basically synonyms. The only difference is class defaults to private members while struct defaults to public members.
Yes, that is an unfortunate legacy of the history of C++. Personally, I would prefer if only one of the keywords "class" and "struct" existed. I also don't think that relying on defaults is a good idea, since those can easily be overlooked or forgotten, and I prefer my code to be more explicit.
Having said that, I use the following convention (which also matches the coding style of a big former employer): A struct has only data in it, and no methods. Everything in a struct is public. If there are compiler-generated methods, they will be trivial, and don't need to be mentioned.
Why? I like placing all of the public members at the top of the class. I can peek at the header file to see the public API - usually without the need to scroll down.
Here's my convention, YMMV. The "big four" (default constructor, copy constructor, operator= and destructor) always go at the very top, in that order. If they are not public, it needs to be commented why not. If compiler-generated versions are used, the prototype for them is still in the source, commented out, with the comment showing that we're using the compiler generated one.
After that, the other methods are ordered roughly by importance to the user of the class. Which usually means the public ones come first, then protected, then internal implementation helpers and private. Data comes last. But for large classes (with say more than a dozen methods in them), it may make sense to group them by functionality. For example for the purple flying elephant class, first everything relating to its color (in that section ordered public/protected/private), then everything about locomotion and flying (same order), then nutrition and health maintenance. If that is done, but a comment at the top explaining the order, and where to find things: public functions for brushing teeth will come after all the functions (public and private) for flapping the ears and steering the flight path.
The order of things in the .C file exactly matches the order in the .h file. I try to have different comments in the two files: The header file explains how to use this class; the implementation file how it works internally. But that is often not a clear distinction (since design decisions usually affect both), so there will be some repetition in the comments. This is one of the reasons why I prefer languages such as Java and Python where a source module is described in a single file.
In general, I hate overuse of the DRY principle. Indeed, having the same text (whether code, comment, or design document) in two places is a maintenance problem, and should be avoided. But having a comment somewhere that the answer can be found in another place is helpful, even if it offends DRY bigots.
In the real world, source files tend to get long. The theory of "files under 100 lines, ideally 24 lines, and tiny commits" doesn't work in the real world, as it fragments coherent pieces of code and changes into grains of sand that are hard to understand. Given that source files are long, one needs a convention for how to group them into sections, just like big books are grouped into volumes, chapters, sections, paragraphs and so forth. For example:
C:
// ==========================================================================
// THIS IS A BIG CHAPTER. IT WILL BE LONG. IT EXPLAINS THE LIFE OF A PENGUIN.
// --------------- This is a section heading. How a penguin moves.
// This code assumes that house and hole have been initialized above.
// The next few lines of code implement the penguin pattern:
penguin* pengy = new EmperorPenguin(...);
if (polar_bar.near(pengy)) {
pengy.hide(hole)
}
But the really important part is this: When I work in a group of people, we will all agree on the conventions. For example, my colleagues and I all know that "long line of equal signs going all the way across the screen means a new and long chapter of code and comments are starting here". And they know that we don't use Hungarian notation: the fact that the name of my penguin starts with "p" is not because it is a pointer, but because that's its name.
Feel free to applaud or (more likely) object.
Nice pun.