.h and .cpp

Discussion in 'C++' started by Christopher, Nov 28, 2011.

  1. Christopher

    Christopher Guest

    If you were on a team of developers that had little C++ experience,
    how would you go about explaining the reasoning as to why the
    following rules should be followed? (Or why they shouldn't)

    1) Class defintions go in their own .h (or .hpp for templates) file
    named after the class
    1a) Every class should have its own .h (or .hpp for templates) file
    1b) A .h file should never contain class implementation (except for
    inline functions or methods)

    2) Class implementations go in their own .cpp file (except for
    templates)
    2a) A .cpp should never contain a class definition

    3) One should not define multiple classes in a single .h file
    3a) Nested class defintions should be avoided without good reason
    (what's good reason?)

    6) Variables should never be defined in a .h file
    7) Globals should not be defined in a .h file
    8) Every .cpp file should compile into a .obj file without error or
    warning on its own.
    i.e In Visual Studio, you should be able to right click a .cpp in
    the source tree and choose compile, without error or warning in the
    output.
    ----

    Sadly, I find myself having to justify these things. (of course
    someone might point out I am wrong or exceptions to the above), but
    these are things that I've always had drilled into my head throughout
    the years and have rarely come acorss other developers that didn't do
    the same. I am finding it frustrating to work on a project where 30
    classes defintions reside in the .h same .h file, a single .cpp file,
    or worse a precompiled header. There is discussion, but I have to
    explain reasoning.

    So far, I've come up with the testability argument:
    When unit testing one frequently wants to test a single class. A proxy
    class may need to be created to test its protected or privare methods.
    Proxies may have to be created for its input and outputs. I should be
    able to include a single .h file, link in the appropriate .obj files
    and compile a unit test without the added clutter of satisfying
    includes or linkage needed by unrelated classes.

    I don't know what else to say aside from, "just do it, its the thing
    to do." and noone is going to buy that.
     
    Christopher, Nov 28, 2011
    #1
    1. Advertising

  2. Christopher

    ralph Guest

    On Mon, 28 Nov 2011 09:20:13 -0800 (PST), Christopher
    <> wrote:

    >If you were on a team of developers that had little C++ experience,
    >how would you go about explaining the reasoning as to why the
    >following rules should be followed? (Or why they shouldn't)
    >
    >1) Class defintions go in their own .h (or .hpp for templates) file
    >named after the class
    >1a) Every class should have its own .h (or .hpp for templates) file
    >1b) A .h file should never contain class implementation (except for
    >inline functions or methods)
    >
    >2) Class implementations go in their own .cpp file (except for
    >templates)
    >2a) A .cpp should never contain a class definition
    >
    >3) One should not define multiple classes in a single .h file
    >3a) Nested class defintions should be avoided without good reason
    >(what's good reason?)
    >
    >6) Variables should never be defined in a .h file
    >7) Globals should not be defined in a .h file
    >8) Every .cpp file should compile into a .obj file without error or
    >warning on its own.
    > i.e In Visual Studio, you should be able to right click a .cpp in
    >the source tree and choose compile, without error or warning in the
    >output.
    >----
    >
    >Sadly, I find myself having to justify these things. (of course
    >someone might point out I am wrong or exceptions to the above), but
    >these are things that I've always had drilled into my head throughout
    >the years and have rarely come acorss other developers that didn't do
    >the same. I am finding it frustrating to work on a project where 30
    >classes defintions reside in the .h same .h file, a single .cpp file,
    >or worse a precompiled header. There is discussion, but I have to
    >explain reasoning.
    >
    >So far, I've come up with the testability argument:
    >When unit testing one frequently wants to test a single class. A proxy
    >class may need to be created to test its protected or privare methods.
    >Proxies may have to be created for its input and outputs. I should be
    >able to include a single .h file, link in the appropriate .obj files
    >and compile a unit test without the added clutter of satisfying
    >includes or linkage needed by unrelated classes.
    >
    >I don't know what else to say aside from, "just do it, its the thing
    >to do." and noone is going to buy that.
    >


    Sounds like a group out-of-control.

    Sadly you either have the authority to enforce coding standards, or
    you do not. If you do then "just do it, its the thing to do" OR *its
    your job* is the only reliable answer. Otherwise, live with it chewing
    away as opportunities present themselves, or seek other employment.

    Number 8 above
    "8) Every .cpp file should compile into a .obj file without error
    or warning on its own"
    can be corrected with daily builds and penalties for "breaking the
    build".

    -ralph
     
    ralph, Nov 28, 2011
    #2
    1. Advertising

  3. Christopher

    Christopher Guest

    > It seems irrational to me to have classes in .h and templates in .hpp;
    > either use .h for all C++ code; .hpp for all C++ code.
    >
    > It seems popular to use .hpp for C++ code and .h for C code these days.
    >
    > /Leigh


    That would be fine with me.
    I am looking for some explanation I can give though for why not to put
    a class definition in a .cpp file. What would you say?
     
    Christopher, Nov 28, 2011
    #3
  4. On 28.11.2011 18:20, Christopher wrote:
    > If you were on a team of developers that had little C++ experience,
    > how would you go about explaining the reasoning as to why the
    > following rules should be followed? (Or why they shouldn't)
    >
    > 1) Class defintions go in their own .h (or .hpp for templates) file
    > named after the class
    > 1a) Every class should have its own .h (or .hpp for templates) file


    Instead of such mechanical rules, have a rule about clarity and possibly
    about testability.

    Two or more classes may be strongly coupled and belong in the same header.

    Many classes are just implementation details and do not deserve their
    own headers.


    > 1b) A .h file should never contain class implementation (except for
    > inline functions or methods)


    The "except" makes this rule self-contradictory.

    Perhaps the author intended to write a rule about always making sure
    that a function definition in a header file is `inline`, whether
    explicitly or implicitly by being defined in a class definition.



    > 2) Class implementations go in their own .cpp file (except for
    > templates)


    That might help to reduce build times for a complex system.

    But note that "complex" is an euphemism for "spaghetti".

    Better, IMO, to instead avoid the spaghetti.


    > 2a) A .cpp should never contain a class definition


    That's incredibly restricting.

    For example, it would preclude the ordinary PIMPL idiom, or else force
    an extra header file for that.


    > 3) One should not define multiple classes in a single .h file
    > 3a) Nested class defintions should be avoided without good reason
    > (what's good reason?)


    These two rules contradict each other.


    > 6) Variables should never be defined in a .h file


    That's idiotic, it precludes defining constants.


    > 7) Globals should not be defined in a .h file


    It's a good idea to avoid global variables in general.

    But this connection with .h files is meaningless.


    > 8) Every .cpp file should compile into a .obj file without error or
    > warning on its own.


    Good idea, and I do agree, although many people disagree.

    Those who disagree find it more work to structure the code so as to get
    rid of warnings, than to merely ignore the warnings, and they argue that
    it is futile to try to shut up future compiler versions.

    For example, building the Boost library produces a lot of warnings.


    > i.e In Visual Studio, you should be able to right click a .cpp in
    > the source tree and choose compile, without error or warning in the
    > output.


    Yes, I think that's a good ideal.

    Also, with any compiler, remember to enable a higher warning level than
    default, but not so extreme as to be impractical.

    For example, with Visual C++ use at least /W4, and with g++ use at least
    -Wall


    > ----
    >
    > Sadly, I find myself having to justify these things. (of course
    > someone might point out I am wrong or exceptions to the above), but
    > these are things that I've always had drilled into my head throughout
    > the years and have rarely come acorss other developers that didn't do
    > the same.


    Oh, you've been unfortunate.


    > I am finding it frustrating to work on a project where 30
    > classes defintions reside in the .h same .h file, a single .cpp file,
    > or worse a precompiled header.


    Yes, that's bad, but I think not solvable by mechanical rules that are
    just as bad (in the other direction).


    > There is discussion, but I have to
    > explain reasoning.
    >
    > So far, I've come up with the testability argument:
    > When unit testing one frequently wants to test a single class. A proxy
    > class may need to be created to test its protected or privare methods.
    > Proxies may have to be created for its input and outputs. I should be
    > able to include a single .h file, link in the appropriate .obj files
    > and compile a unit test without the added clutter of satisfying
    > includes or linkage needed by unrelated classes.
    >
    > I don't know what else to say aside from, "just do it, its the thing
    > to do." and noone is going to buy that.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Nov 28, 2011
    #4
  5. Christopher

    Christopher Guest

    > Sounds like a group out-of-control.
    >
    > Sadly you either have the authority to enforce coding standards, or
    > you do not. If you do then "just do it, its the thing to do" OR *its
    > your job* is the only reliable answer. Otherwise, live with it chewing
    > away as opportunities present themselves, or seek other employment.


    I am beginning to think that might be the case, but if the boss says
    "I beleive you, you just have to give some reasoning aside from I said
    so." Then I wanted to at least try before joining the "I am looking
    for employment" group again.

    > Number 8 above
    > "8) Every .cpp file should compile into a .obj file without error
    >  or warning on its own"
    > can be corrected with daily builds and penalties for "breaking the
    > build".


    Not really, because the build in its entirety brings in other .cpp
    and .h files as well as precompiled headers, in which things were
    defined in the wrong places, but the compiler remains happy. It just
    ends up being a fragile build that breaks often, because standards
    weren't followed. When compiling just one .cpp by itself, everything
    has to be defined and correct.
     
    Christopher, Nov 28, 2011
    #5
  6. Christopher

    Goran Guest

    On Nov 28, 6:20 pm, Christopher <> wrote:
    > If you were on a team of developers that had little C++ experience,
    > how would you go about explaining the reasoning as to why the
    > following rules should be followed? (Or why they shouldn't)
    >
    > 1) Class defintions go in their own .h (or .hpp for templates) file
    > named after the class


    Don't know about hpp for templates. It's *.h or *.hpp for everything
    if you ask me. If there is only one class ion the file, or if it's
    clearly the "main" class in it, then class_name.h is only natural.

    > 1a) Every class should have its own .h (or .hpp for templates) file


    Not so sure about that. All sorts of auxiliary artifacts can just as
    well be tagged along their principal stuff.

    > 1b) A .h file should never contain class implementation (except for
    > inline functions or methods)


    Purely mechanically, this doesn't work due to C compilation model: if
    the class parts are defined in a header, and said header is included
    in more than one translation unit (source file), linker will encounter
    duplicate symbols.

    > 2) Class implementations go in their own .cpp file (except for
    > templates)


    Same as above

    > 2a) A .cpp should never contain a class definition


    Disagreed. There's classes that will only be used in one translation
    unit. What can one gain by making another trivial header?

    > 3) One should not define multiple classes in a single .h file
    > 3a) Nested class defintions should be avoided without good reason
    > (what's good reason?)


    Good reason: nested class is used exclusively in context of the
    nesting class, possibly as a helper.

    Private nested classes should be avoided. They are better off in
    implementation file, as not to create additional compile-time
    dependency where there's no logical one.

    > 6) Variables should never be defined in a .h file


    Same as for classes - duplicate symbols galore. Exception: literal
    constants. If these are not constants, there should ideally be 0 of
    those in any given codebase.

    > 7) Globals should not be defined in a .h file


    I am not sure to understand the difference between a variable and a
    global?

    > 8) Every .cpp file should compile into a .obj file without error or
    > warning on its own.
    >      i.e In Visual Studio, you should be able to right click a .cppin
    > the source tree and choose compile, without error or warning in the
    > output.


    Except for precompiler header, which one should be using to save
    compilation time. IOW, if precompiled header is used and compiled,
    then any translation unit should compile.

    Otherwise, if you can't compile without errors, you can't compile, end
    of, so that's a given. As for warnings... When compiler emits a
    warning, it does it for a reason. Coder isn't smarter than compiler as
    far as formal verification goes. If there's a warning, coder should
    first try to change the code so that compiler has no reason for
    nagging. That usually ends in a better design. Casting or other
    compiler-gagging come distant second as idea.

    > Sadly, I find myself having to justify these things.


    Sadly is a good word. What, do directory entries cost these people
    money?

    > (of course
    > someone might point out I am wrong or exceptions to the above), but
    > these are things that I've always had drilled into my head throughout
    > the years and have rarely come acorss other developers that didn't do
    > the same. I am finding it frustrating to work on a project where 30
    > classes defintions reside in the .h same .h file, a single .cpp file,
    > or worse a precompiled header. There is discussion, but I have to
    > explain reasoning.


    Ugh. That's a clear-cut sign that someone doesn't know how to work
    with C compilation model.

    Goran.
     
    Goran, Nov 28, 2011
    #6
  7. Christopher <> wrote:
    >> It seems irrational to me to have classes in .h and templates in .hpp;
    >> either use .h for all C++ code; .hpp for all C++ code.
    >>
    >> It seems popular to use .hpp for C++ code and .h for C code these days.
    >>
    >> /Leigh

    >
    > That would be fine with me.
    > I am looking for some explanation I can give though for why not to put
    > a class definition in a .cpp file. What would you say?


    Generally, you don't #include .cpp files (this is what .h files are made
    for), so a class defined in a cpp file is really only visible in that
    single file.

    Normally you want a class to be reusable in other files, but there are rare
    cases where it makes sense to have a class that is "private" to some .cpp
    file and you don't want it to be used by others.

    Tobi
     
    Tobias Müller, Nov 28, 2011
    #7
  8. On 28.11.2011 20:03, Leigh Johnston wrote:
    > On 28/11/2011 18:45, Alf P. Steinbach wrote:
    >> On 28.11.2011 18:20, Christopher wrote:
    >>
    >>> 6) Variables should never be defined in a .h file

    >>
    >> That's idiotic, it precludes defining constants.

    >
    > Traditionally constants are called constants not variables.


    You got a point.

    I was associating too strongly to formal terminology.


    Cheers, & thanks,

    - Alf
     
    Alf P. Steinbach, Nov 28, 2011
    #8
  9. Christopher

    Rui Maciel Guest

    Christopher wrote:

    > If you were on a team of developers that had little C++ experience,
    > how would you go about explaining the reasoning as to why the
    > following rules should be followed? (Or why they shouldn't)
    >
    > 1) Class defintions go in their own .h (or .hpp for templates) file
    > named after the class
    > 1a) Every class should have its own .h (or .hpp for templates) file
    > 1b) A .h file should never contain class implementation (except for
    > inline functions or methods)
    >
    > 2) Class implementations go in their own .cpp file (except for
    > templates)
    > 2a) A .cpp should never contain a class definition
    >
    > 3) One should not define multiple classes in a single .h file
    > 3a) Nested class defintions should be avoided without good reason
    > (what's good reason?)
    >
    > 6) Variables should never be defined in a .h file
    > 7) Globals should not be defined in a .h file
    > 8) Every .cpp file should compile into a .obj file without error or
    > warning on its own.
    > i.e In Visual Studio, you should be able to right click a .cpp in
    > the source tree and choose compile, without error or warning in the
    > output.
    > ----
    >
    > Sadly, I find myself having to justify these things. (of course
    > someone might point out I am wrong or exceptions to the above), but
    > these are things that I've always had drilled into my head throughout
    > the years and have rarely come acorss other developers that didn't do
    > the same. I am finding it frustrating to work on a project where 30
    > classes defintions reside in the .h same .h file, a single .cpp file,
    > or worse a precompiled header. There is discussion, but I have to
    > explain reasoning.


    Separating declarations from implementations and mandating that each class
    should be defined and implemented in separate source files are a couple of
    practices which help track what changes were made to each individual
    component and who made those changes. With this, auditing the code becomes
    a bit simpler.

    This practice also reduces the amount of potential merging conflicts any
    commit might induce.


    Rui Maciel
     
    Rui Maciel, Nov 28, 2011
    #9
  10. Christopher

    Geoff Guest

    Geoff, Nov 28, 2011
    #10
  11. Christopher

    ralph Guest

    On Mon, 28 Nov 2011 10:48:17 -0800 (PST), Christopher
    <> wrote:

    >> Sounds like a group out-of-control.
    >>
    >> Sadly you either have the authority to enforce coding standards, or
    >> you do not. If you do then "just do it, its the thing to do" OR *its
    >> your job* is the only reliable answer. Otherwise, live with it chewing
    >> away as opportunities present themselves, or seek other employment.

    >
    >I am beginning to think that might be the case, but if the boss says
    >"I beleive you, you just have to give some reasoning aside from I said
    >so." Then I wanted to at least try before joining the "I am looking
    >for employment" group again.
    >
    >> Number 8 above
    >> "8) Every .cpp file should compile into a .obj file without error
    >>  or warning on its own"
    >> can be corrected with daily builds and penalties for "breaking the
    >> build".

    >
    >Not really, because the build in its entirety brings in other .cpp
    >and .h files as well as precompiled headers, in which things were
    >defined in the wrong places, but the compiler remains happy. It just
    >ends up being a fragile build that breaks often, because standards
    >weren't followed. When compiling just one .cpp by itself, everything
    >has to be defined and correct.


    I was thinking of intermediate or validation "builds" as part of the
    daily build. Which is something I often enforce with large projects,
    ie, no translation unit gets through with warnings and errors. Even
    so, as you noted, the build is fragile and will destruct sooner or
    later. Making those responsible for breaking the build - responsible
    for repairing the build, will go a long way to getting the message
    across.

    Also frequent Code Reviews will help.

    Setting up and maintaining an enterprise level development effort is
    not a trivial exercise. It encompasses more that just "coding
    standards".

    As others noted not all your rules are "unquestionable". Few *best
    practices* are. There are always exceptions, though as the proverb
    says "it is the exception that makes the rule".

    You have to start somewhere. Having a good reason to break a rule is
    very useful in gaining an understanding of why the rule was there in
    the first place.

    Hold on. Chew away. Be happy if you can make a change. Don't beat
    yourself up when you can't. (ie, don't take it home with you. <g>)

    -ralph
     
    ralph, Nov 28, 2011
    #11
  12. Christopher

    Christopher Guest

    On Nov 28, 12:58 pm, Goran <> wrote:
    > > 1a) Every class should have its own .h (or .hpp for templates) file

    >
    > Not so sure about that. All sorts of auxiliary artifacts can just as
    > well be tagged along their principal stuff.


    I suppose a functor used for comparison might be an example. I need to
    explain somehow what kinds of things would be an auxilary artifact
    that is acceptable and what obviously requires seperation. I suppose
    it is just intuitive to most of us.

    I think what was said about nested classes is a good start. If the
    class is only used by the main class in the file.


    > > 1b) A .h file should never contain class implementation (except for
    > > inline functions or methods)

    >
    > Purely mechanically, this doesn't work due to C compilation model: if
    > the class parts are defined in a header, and said header is included
    > in more than one translation unit (source file), linker will encounter
    > duplicate symbols.
    > > 2) Class implementations go in their own .cpp file (except for
    > > templates)

    >
    > Same as above
    >


    I cannot visualize this scenario. Can you give a code example in which
    any part of class implementation is required to be in the header,
    excluding the use of templates?

    Use of inclusion guards has always taken care of duplicate symbols
    when a header is included in more than one source file and is pretty
    standard practice in my experience.



    > > 2a) A .cpp should never contain a class definition

    >
    > Disagreed. There's classes that will only be used in one translation
    > unit. What can one gain by making another trivial header?


    In this case, what's wrong with putting it in the header? I suppose
    until I can visualize your argument for 1b and 2, I have trouble
    seeing this as well.

    When I see an unfamilair type in a source file, I would immeditaley
    look in the corresponding .h file for its defintion. I'd hate to rely
    on "not-so-intelli-sense" or something similar.

    If inclusion guards are used, I don't see the down side.


    > > 3) One should not define multiple classes in a single .h file
    > > 3a) Nested class defintions should be avoided without good reason
    > > (what's good reason?)

    >
    > Good reason: nested class is used exclusively in context of the
    > nesting class, possibly as a helper.


    Good reason!


    > Private nested classes should be avoided. They are better off in
    > implementation file, as not to create additional compile-time
    > dependency where there's no logical one.


    I could see this making sense pending more explanation to the previous
    arguments.


    > > 6) Variables should never be defined in a .h file

    >
    > Same as for classes - duplicate symbols galore. Exception: literal
    > constants. If these are not constants, there should ideally be 0 of
    > those in any given codebase.


    Whoops, I believe I meant to say variable _declaration_. Definition
    and Declaration seem to very confusing terms as they have different
    meanings for classes and variables in C++.

    What I mean is
    int x = 10; should not appear in a .h file.
    int x; However, may appear in a .h file, but I'd still argue that
    there is probably a better way then using a global.

    const int x = 10; Should not appear in a .h file
    const int x; May appear in a .h file, but I'd rather see:

    static int GetX() const
    {
    return 10;
    }

    because some other global MyClass might make use of x and then I run
    into the static intialization fiasco.


    or better if only used in one class:

    class WhereXIsUsed
    {
    public:
    private:
    const int m_x;
    };

    or possibly something like

    struct SystemConfigurationDefaults
    {
    const int m_x;
    };


    > > 7) Globals should not be defined in a .h file

    >
    > I am not sure to understand the difference between a variable and a
    > global?


    One is a superset of the other.
    But again, I think I meant declared instead.



    > > 8) Every .cpp file should compile into a .obj file without error or
    > > warning on its own.
    > >      i.e In Visual Studio, you should be able to right click a .cpp in
    > > the source tree and choose compile, without error or warning in the
    > > output.

    >
    > Except for precompiler header, which one should be using to save
    > compilation time. IOW, if precompiled header is used and compiled,
    > then any translation unit should compile.


    When it comes to precompiled headers, what I am trying to convey is
    that everything should compile without them.
    Precomiled headers should be used as a build optimization only, if at
    all, and not as part of the implementation.

    How I've been doing it:

    ---
    /*
    * foo.h
    */
    #ifndef FOO_H
    #define FOO_H

    #include <iostream>

    // Use of iostream
    // SNIP
    #endif

    ---
    /*
    * foo.cpp
    */
    #include "precompiled-header.h"
    #include "foo.h"

    #include <algorithm>

    // Use of algorithm
    //SNIP

    ---
    /*
    * precompiled-header.h
    */
    #include <algorithm>
    #include <iostream>
    // SNIP

    Allows for foo.obj regardless of whether or not the precompiled header
    was compiled. If the pre-compiled header was used, it speeds up build
    time in some scenarios.


    What I've come across that I believe is incorrect, but still compiles
    if build order happens to work out:
    ---
    /*
    * foo.h
    */
    #ifndef FOO_H
    #define FOO_H

    // Use of iostream
    // SNIP
    #endif

    ---
    /*
    * foo.cpp
    */
    #include "precompiled-header.h"

    // Use of algorithm
    //SNIP

    ---
    /*
    * precompiled-header.h
    */
    #include "foo.h"

    #include <algorithm>
    #include <iostream>
    // SNIP

    My difficulty, assuming I am correct (because I am totally willing to
    accept correction with explanation), is expressing this in words.


    > Sadly is a good word. What, do directory entries cost these people
    > money?


    I've heard words like "complexity" and "clutter"
    Ironic, because I use words like "simple" and "logical"
     
    Christopher, Nov 28, 2011
    #12
  13. Christopher

    Ian Collins Guest

    On 11/29/11 09:17 AM, Geoff wrote:
    > I disagree with your rule 6. It precludes #define.


    Which was "Variables should never be defined in a .h file". Context is
    good.


    Why would you be using #define for variables in C++?

    --
    Ian Collins
     
    Ian Collins, Nov 28, 2011
    #13
  14. Christopher

    Jorgen Grahn Guest

    On Mon, 2011-11-28, Alf P. Steinbach wrote:
    > On 28.11.2011 18:20, Christopher wrote:
    >> If you were on a team of developers that had little C++ experience,
    >> how would you go about explaining the reasoning as to why the
    >> following rules should be followed? (Or why they shouldn't)

    ....

    >> 1b) A .h file should never contain class implementation (except for
    >> inline functions or methods)

    >
    > The "except" makes this rule self-contradictory.
    >
    > Perhaps the author intended to write a rule about always making sure
    > that a function definition in a header file is `inline`, whether
    > explicitly or implicitly by being defined in a class definition.


    That still does not cover templates though. You may want to define
    template classes, but not ask for inlining of everything.

    ....
    >> i.e In Visual Studio, you should be able to right click a .cpp in
    >> the source tree and choose compile, without error or warning in the
    >> output.

    >
    > Yes, I think that's a good ideal.
    >
    > Also, with any compiler, remember to enable a higher warning level than
    > default, but not so extreme as to be impractical.
    >
    > For example, with Visual C++ use at least /W4, and with g++ use at least
    > -Wall


    I've mentioned it before, but IMHO -Wall is far from enough. I default
    to

    -Wall -Wextra -pedantic -std=c++98 -g -O3

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Nov 28, 2011
    #14
  15. Christopher <> wrote:
    > Use of inclusion guards has always taken care of duplicate symbols
    > when a header is included in more than one source file and is pretty
    > standard practice in my experience.


    Inclusion guards don't help you here, at least if you have more than one
    translation unit.

    Inclusion guards make sure that you don't have duplicate class definitions
    in one TU. However, every header file needs to be visible in every TU or
    else you can't use the classes defined in that header. And if you have
    method implementations in the header, the code will be generated in every
    TU and evetually the linker will complain (not the compiler).

    Tobi
     
    Tobias Müller, Nov 29, 2011
    #15
  16. Christopher <> wrote:
    > 1) Class defintions go in their own .h (or .hpp for templates) file
    > named after the class


    I never use ".h" as a file name extension for C++ headers for a rather
    obvious reason: It's not C code and I want to distinguish C code from C++
    code unambiguously. Also, I don't see why headers containing templated
    code should be named differently from headers that don't.

    From unix I am accustomed to using .cc and .hh extensions, but that's
    another story.

    > 1a) Every class should have its own .h (or .hpp for templates) file


    You are polluting the global namespace this way for classes that could
    well be compilation-unit-local. Such classes should go into a nameless
    namespace, which is incompatible with a public header file. (Ok,
    technically speaking you can put a nameless namespace in a header file
    because, after all, it's just C++ code like everything else, but the
    advantage of doing this is dubious. You will only be including it in
    the compilation unit where it's used, and including it anywhere else
    would be useless, as it would only define an unimplemented local class.)

    You might have learned otherwise, but I have learned that public interfaces
    should be as minimal as possible, and polluting the global namespace with
    local types is not good design.

    > 1b) A .h file should never contain class implementation (except for
    > inline functions or methods)


    That's a null statement. If a header file contains implementations,
    they will be inline by necessity (else you'll get linker errors if the
    header is included more than once), so that rule isn't really saying
    anything.

    Perhaps if you had said: "A header file should contain inline function
    implementations only if there's a very good reason for them. Otherwise
    they should go to the correspondent compilation unit."

    > 2) Class implementations go in their own .cpp file (except for
    > templates)


    Technically speaking templates can be declared in a header file and
    implemented in a compilation unit even in cases where the template is
    used somewhere else besides that compilation unit (yes, even without
    support for export; it can be done with explicit template instantiation),
    but that's not a usual circumstance. But I digress.

    > 2a) A .cpp should never contain a class definition


    Why not? If a class is used only in that one compilation unit, and
    especially if it's small, what's the problem?

    Think about this: What would be the difference between a private inner
    class and a class local to the compilation unit (ie. in a nameless namespace),
    except for scope? Would the former be ok but not the latter? Why?
    (The testability argument doesn't hold because you cannot test a private
    inner class from the outside.)

    (And please don't tell me you oppose private inner classes too.)

    > 3) One should not define multiple classes in a single .h file


    If two classes are relatively small and strongly related to one other,
    why not? A typical example would be a template class and a specialization
    for a specific template type. If you put them in separate header files, you
    would have a small problem in what to include. There are many non-templated
    examples as well.

    > 3a) Nested class defintions should be avoided without good reason
    > (what's good reason?)


    I don't see why inner classes "should be avoided".

    In general class design should be as simple as possible. That includes,
    among many other things, minimizing the amount of inner classes. However,
    there's nothing special about them in particular that should be avoided.

    Iterators are good examples of public inner classes. Why should they be
    avoided? And if some private implementation of the class needs a private
    class, then why not? (In fact, sometimes trying to religiously avoid inner
    classes can make your code much more complicated and harder to manage.)

    > 6) Variables should never be defined in a .h file


    There are some situations where extern variables are justified. Although
    even in those cases they should usually be declared inside a namespace to
    minimize global namespace pollution. (std::cout would be an example.)

    > 7) Globals should not be defined in a .h file


    Well, duh. You'll get a linker error if you do. (At least if you include
    the header in more than one place.)

    > 8) Every .cpp file should compile into a .obj file without error or
    > warning on its own.


    Hmm, is there any other way? Or what do you mean "on its own"? I don't
    even know of any other way of compiling a C++ program than one compilation
    unit at a time.
     
    Juha Nieminen, Nov 29, 2011
    #16
  17. Christopher

    Goran Guest

    On Nov 28, 9:17 pm, Geoff <> wrote:
    > I disagree with your rule 6. It precludes #define.
    >
    > Also, rule number 6: there is no rule 6!
    > (Obligatory Monty Python reference.)
    >
    > For some very interesting coding standards referenced by no less
    > authority than Stroustrup himself:
    >
    > http://www2.research.att.com/~bs/JSF-AV-rules.pdf
    >
    > via his page:http://www2.research.att.com/~bs/C .html


    +1. This is "C++ for embedded systems bible" IMHO.

    Goran.
     
    Goran, Nov 29, 2011
    #17
  18. Christopher

    Goran Guest

    On Nov 28, 10:30 pm, Christopher <> wrote:
    > On Nov 28, 12:58 pm, Goran <> wrote:
    >
    > > > 1a) Every class should have its own .h (or .hpp for templates) file

    >
    > > Not so sure about that. All sorts of auxiliary artifacts can just as
    > > well be tagged along their principal stuff.

    >
    > I suppose a functor used for comparison might be an example. I need to
    > explain somehow what kinds of things would be an auxilary artifact
    > that is acceptable and what obviously requires seperation. I suppose
    > it is just intuitive to most of us.
    >
    > I think what was said about nested classes is a good start. If the
    > class is only used by the main class in the file.
    >
    > > > 1b) A .h file should never contain class implementation (except for
    > > > inline functions or methods)

    >
    > > Purely mechanically, this doesn't work due to C compilation model: if
    > > the class parts are defined in a header, and said header is included
    > > in more than one translation unit (source file), linker will encounter
    > > duplicate symbols.
    > > > 2) Class implementations go in their own .cpp file (except for
    > > > templates)

    >
    > > Same as above

    >
    > I cannot visualize this scenario. Can you give a code example in which
    > any part of class implementation is required to be in the header,
    > excluding the use of templates?


    I poorly expressed myself? When I said "same as above", I meant "you
    have to put class implementation in it's own implementation because
    otherwise linker encounters duplicate symbols". So class
    implementations absolutely must go in an implementation file. Perhaps
    it's own implementation file (e.g. small related thingy can tag
    along).

    >
    > Use of inclusion guards has always taken care of duplicate symbols
    > when a header is included in more than one source file and is pretty
    > standard practice in my experience.
    >
    > > > 2a) A .cpp should never contain a class definition

    >
    > > Disagreed. There's classes that will only be used in one translation
    > > unit. What can one gain by making another trivial header?

    >
    > In this case, what's wrong with putting it in the header? I suppose
    > until I can visualize your argument for 1b and 2, I have trouble
    > seeing this as well.


    If code artifact is used in only one translation unit, it does not
    require a header, that's all. Make it if you wish, but it's only more
    files to go around.

    > When I see an unfamilair type in a source file, I would immeditaley
    > look in the corresponding .h file for its defintion. I'd hate to rely
    > on "not-so-intelli-sense" or something similar.


    What's wrong with grep or "Find in files" in VS?

    > If inclusion guards are used, I don't see the down side.
    >
    > > > 3) One should not define multiple classes in a single .h file
    > > > 3a) Nested class defintions should be avoided without good reason
    > > > (what's good reason?)

    >
    > > Good reason: nested class is used exclusively in context of the
    > > nesting class, possibly as a helper.

    >
    > Good reason!
    >
    > > Private nested classes should be avoided. They are better off in
    > > implementation file, as not to create additional compile-time
    > > dependency where there's no logical one.

    >
    > I could see this making sense pending more explanation to the previous
    > arguments.
    >
    > > > 6) Variables should never be defined in a .h file

    >
    > > Same as for classes - duplicate symbols galore. Exception: literal
    > > constants. If these are not constants, there should ideally be 0 of
    > > those in any given codebase.

    >
    > Whoops, I believe I meant to say variable _declaration_. Definition
    > and Declaration seem to very confusing terms as they have different
    > meanings for classes and variables in C++.
    >
    > What I mean is
    > int x = 10; should not appear in a .h file.


    That doesn't work anyhow. For example (it's the example you're asking
    for elsewhere, too), you can compile (BUT NOT LINK)

    h.h
    #ifndef whatever
    #define whatever
    int x=10;
    #endif

    s.cpp
    #include "h.h"
    void f()
    {
    x++;
    }

    main.cpp
    #include "h.h"
    int main(int, const char*[])
    {
    x++
    }

    > int x; However, may appear in a .h file, but I'd still argue that
    > there is probably a better way then using a global.


    I like

    extern int x;

    (explains the intent better IMO)

    > const int x = 10; Should not appear in a .h file
    > const int x; May appear in a .h file, but I'd rather see:
    >
    > static int GetX() const
    > {
    >    return 10;
    >
    > }
    >
    > because some other global MyClass might make use of x and then I run
    > into the static intialization fiasco.
    >
    > or better if only used in one class:
    >
    > class WhereXIsUsed
    > {
    > public:
    > private:
    >   const int m_x;
    >
    > };


    If only used in one class, it's best declared in class's
    implementation. That's (for me) to avoid compile-time dependency: you
    can change it in *.cpp all you like, you don't recompile all other
    *.cpp-s that include your_class.h

    >
    > or possibly something like
    >
    > struct SystemConfigurationDefaults
    > {
    >    const int m_x;
    >
    > };
    > > > 7) Globals should not be defined in a .h file

    >
    > > I am not sure to understand the difference between a variable and a
    > > global?

    >
    > One is a superset of the other.
    > But again, I think I meant declared instead.
    >
    > > > 8) Every .cpp file should compile into a .obj file without error or
    > > > warning on its own.
    > > >      i.e In Visual Studio, you should be able to right click a ..cpp in
    > > > the source tree and choose compile, without error or warning in the
    > > > output.

    >
    > > Except for precompiler header, which one should be using to save
    > > compilation time. IOW, if precompiled header is used and compiled,
    > > then any translation unit should compile.

    >
    > When it comes to precompiled headers, what I am trying to convey is
    > that everything should compile without them.
    > Precomiled headers should be used as a build optimization only, if at
    > all, and not as part of the implementation.


    Yes, agreed.

    > How I've been doing it:
    >
    > ---
    > /*
    > * foo.h
    > */
    > #ifndef FOO_H
    > #define FOO_H
    >
    > #include <iostream>
    >
    > // Use of iostream
    > // SNIP
    > #endif
    >
    > ---
    > /*
    > * foo.cpp
    > */
    > #include "precompiled-header.h"
    > #include "foo.h"
    >
    > #include <algorithm>
    >
    > // Use of algorithm
    > //SNIP
    >
    > ---
    > /*
    > * precompiled-header.h
    > */
    > #include <algorithm>
    > #include <iostream>
    > // SNIP
    >
    > Allows for foo.obj regardless of whether or not the precompiled header
    > was compiled. If the pre-compiled header was used, it speeds up build
    > time in some scenarios.


    Actually, I like that. I was wrong when I said that you can build
    "provided that precompiled header was built before" (and you are
    right).

    Goran.
     
    Goran, Nov 29, 2011
    #18
  19. On 28.11.2011 19:58, Goran wrote:
    > On Nov 28, 6:20 pm, Christopher<> wrote:
    >
    >> 1b) A .h file should never contain class implementation (except for
    >> inline functions or methods)

    >
    > Purely mechanically, this doesn't work due to C compilation model: if
    > the class parts are defined in a header, and said header is included
    > in more than one translation unit (source file), linker will encounter
    > duplicate symbols.


    I think the above is perhaps too vaguely expressed.

    First, a "class definition" does not necessarily include definitions of
    member functions.

    Secondly, it's quite common to put also definitions of member functions
    in a header. They need then to be either templates or `inline`. For
    example, many Boost sub-libraries are header only.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Nov 29, 2011
    #19
  20. Christopher

    gwowen Guest

    On Nov 28, 10:41 pm, Ian Collins <> wrote:
    > On 11/29/11 09:17 AM, Geoff wrote:
    >
    > > I disagree with your rule 6. It precludes #define.

    >
    > Which was "Variables should never be defined in a .h file".  Context is
    > good.
    >
    > Why would you be using #define for variables in C++?


    In a header, you may want some C/C++ cross compatibility and the C
    definition of what counts as a compile-time constant can make it the
    least-unpleasant way to define a constant.

    romanes.h:
    ------------------------
    const size_t NROMANS = 512;
    #define HOWMANYROMANS 512

    romanes.c
    -----------------
    static int[NFOO]; /* D'oh! Won't compile as C */
    static int[HOWMANYROMANS]; /* Will compile as C*/
     
    gwowen, Nov 29, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DrUg13
    Replies:
    1
    Views:
    477
    DrUg13
    Feb 10, 2004
  2. Alex Vinokur
    Replies:
    7
    Views:
    410
    Greg Comeau
    Nov 15, 2004
  3. Vinu
    Replies:
    9
    Views:
    623
  4. lovecreatesbeauty
    Replies:
    1
    Views:
    1,058
    Ian Collins
    May 9, 2006
  5. www.hitechskill.com
    Replies:
    0
    Views:
    1,353
    www.hitechskill.com
    Apr 9, 2006
Loading...

Share This Page