Wednesday, September 17, 2008

C++ Coding Standard: Implementation Files

Section 4 of the C++ coding standard is so short, that it makes sense to cover the next two sections in one post. We just covered the layout and contents of header files; these sections refer to the layout and contents of implementation files.
  • 4. Implementation file layout has only a few restrictions.
    • 4.1. Implementation files must begin with the standard C++ file comment.
    • 4.2. The first non-comment line of {class}.cpp must be: #include "{class}.hpp".
    • 4.3. {class}.cpp definitions should be in the same order as {class}.hpp declarations.
  • 5. Implementation file (.cpp) contents.
    • 5.1. A .cpp must never include an implementation file.
    • 5.2. A .cpp must not include files not needed to compile itself.
    • 5.3. Every non-inline function declared in {class}.hpp must be defined in {class}.cpp.
      • 5.3.1. Exception to 5.3: copy constructor and assignment operator may be declared private and not implemented, to override C++ defaults.
    • 5.4. Every static member variable declared in {class}.hpp must be defined in {class}.cpp.
    • 5.5. Anything defined in {class}.cpp which is not declared in {class}.hpp must be in the anonymous namespace.
    • 5.6. Every anonymous namespace function must be preceded by a documentation comment.
Rule 4.2 is a trick which ensures that {class}.hpp includes every file needed to compile it (see Rule 3.2). Note that the order of variables and functions in the .cpp file is just a "should" -- it makes for easier reference, but there may be some good reason why the order is different.

I've come to the conclusion that most classes should have a copy constructor and an assignment operator, and I would always implement them rather than let the compiler generate them, even if the naive bitwise copy is correct for the class. But sometimes you decide that an object must not be copyable. Then you use the trick in 5.3.1, you don't define the functions, but you do declare them:

private:
Object(const Object &orig);
Object &operator=(const Object &orig);

Then anyone outside of Object.cpp that tries to take a copy of an Object will get a compile error (any member of Object who takes a copy will get a link error).

Not everyone has yet heard of anonymous namespaces, but about 10 years ago they became the official approved way to declare things which aren't visible outside their source file. You used to declare them static, now do this:

namespace {

int globalForThisFileOnly = 1;
bool functionForThisFileOnly()
{
return true;
}

} // anonymous namespace

Next: Class design.

No comments: