Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > .h and .cpp

Reply
Thread Tools

.h and .cpp

 
 
ralph
Guest
Posts: n/a
 
      11-28-2011
On Mon, 28 Nov 2011 10:48:17 -0800 (PST), Christopher
<(E-Mail Removed)> 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
>> " 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
 
Reply With Quote
 
 
 
 
Christopher
Guest
Posts: n/a
 
      11-28-2011
On Nov 28, 12:58*pm, Goran <(E-Mail Removed)> 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.



> > 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"

 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      11-28-2011
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
 
Reply With Quote
 
Jorgen Grahn
Guest
Posts: n/a
 
      11-28-2011
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 .
 
Reply With Quote
 
Tobias Müller
Guest
Posts: n/a
 
      11-29-2011
Christopher <(E-Mail Removed)> 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
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      11-29-2011
Christopher <(E-Mail Removed)> 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.)

> 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.
 
Reply With Quote
 
Goran
Guest
Posts: n/a
 
      11-29-2011
On Nov 28, 9:17*pm, Geoff <(E-Mail Removed)> 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.
 
Reply With Quote
 
Goran
Guest
Posts: n/a
 
      11-29-2011
On Nov 28, 10:30*pm, Christopher <(E-Mail Removed)> wrote:
> On Nov 28, 12:58*pm, Goran <(E-Mail Removed)> 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.
>
> > > 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.
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      11-29-2011
On 28.11.2011 19:58, Goran wrote:
> On Nov 28, 6:20 pm, Christopher<(E-Mail Removed)> 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
 
Reply With Quote
 
gwowen
Guest
Posts: n/a
 
      11-29-2011
On Nov 28, 10:41*pm, Ian Collins <(E-Mail Removed)> 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*/
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
if and and vs if and,and titi VHDL 4 03-11-2007 05:23 AM



Advertisments