7

So the other day, I was looking through some old C++ books and noticed a way of creating a C++ class I had never seen before. Everything I have seen up to that point had always used the #include "header.h" and compiled the implementation files separately. What I saw the author of this book do is actually put an include directive to the implementation at the end of the header file and omitting the .cpp file from the compilation. Has anybody used this style?

For Example: I have main.cpp employee.h employee.cpp

//main.cpp
#include <iostream>
#include <stdio.h>
#include <string>
#include "employee.h"
void main()
{/*some code*/}  

//employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class employee
{
   public:
   //public members
   private:
   //private members
}
#endif

//employee.cpp
#include "employee.h"
#include <string>
//public member definitions

I would normaly compile this project like so:

g++ main.cpp employee.cpp

But in the author's example is like this

//main.cpp
#include <iostream>
#include <stdio.h>
#include <string>
#include "employee.h"
void main()
{/*some code*/}  

//employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class employee
{
   public:
   //public members
   private:
   //private members
}
#include "employee.cpp"  // <-- the line of code that caught my attention
#endif

//employee.cpp
 #include <string>
//public member definitions

And the resulting code compiles as

g++ main.cpp

Is this merely a style preference or are there any real benefits in this? I would think it wouldn't scale very well, but I am not a super proficient C++ programmer either.

Chad Harrison
  • 2,836
  • 4
  • 33
  • 50
  • 4
    Yeah, I'd like to avoid that book too. – Beta Jun 03 '11 at 16:27
  • @Neil "C++ Classes and Data Structures" by Jeffrey S. Childs ISBN 0-13-158051-5 978-0-13-1558051-0. Actually its not that old at, this book has a copy right of 2008 – Chad Harrison Jun 03 '11 at 16:27
  • @Matt, it will not be an issue as there are include guards, but it is surely not the recommended approach. – David Rodríguez - dribeas Jun 03 '11 at 16:30
  • 4
    @Beta I would say it a little stronger. Run like hell from that book!!! It seems the book is rated slightly higher than 2 stars at [amazon](http://www.amazon.com/C-Classes-Structures-Jeffrey-Childs/dp/0131580515/ref=sr_1_1?ie=UTF8&qid=1307118639&sr=8-1), mostly for the awful examples. – Lou Jun 03 '11 at 16:30
  • +1 for showing me which book to avoid. :) – Xeo Jun 03 '11 at 16:36
  • Thanks for everybody's thoughts. I am glad I wasn't the only one who thought it was a bit strange. – Chad Harrison Jun 03 '11 at 16:42
  • Any book that says `void main()`: Run away. If the book also says `#include "foo.cpp"`: Run away as fast as you can. – David Hammen Jun 03 '11 at 16:51
  • @David Hammen: ...and hurry back with some matches. – Beta Jun 03 '11 at 17:02
  • @hydroparadise: It's not necessarily a bad idea to put inline member function definitions in a separate file, included from the main header; but it's definitely a bad idea to give it a `.cpp` extension when it isn't a compilable source file. – Mike Seymour Jun 03 '11 at 17:08

5 Answers5

3

Doing this will bring the definition of the class in to every translation unit where the header file is included. This is a very unusual paradigm, and could be hazardous to your coding health. In particular, if you have main.cpp and foo.cpp both of which #include "employee.h", then all the methods on employee will be defined twice, which is a violation of the One Definition Rule and will create linker errors. In order to resolve those linker errors, you need to either move the definitions to their own translation unit, or mark them inline (which may or may not work).

This is however a useful idiom in some instances. Particularly with templates, which must be defined within the translation unit. In that case, when you want the declaration and implementation in separate files for readability, you can do an end-of-file #include. When I do this, I use a special file extension, .hpp to signify that the file is special in that it is not intended to be compiled on its own. See this answer for an example.

Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    @Richard: the ODR is also about multiple definitions in separate translation units, and include guards do nothing to prevent that. If a header contains non-inline function definitions and it's included in more than one translation unit, then you will get link errors. @John: declaring the functions `inline` *will* fix the linker errors - that's exactly what `inline` is for. – Mike Seymour Jun 03 '11 at 21:43
  • @Mike: Doh - Brain freeze....yes of course you're right! - I've removed the embarrassing comment! – Richard Corden Jun 08 '11 at 12:51
3

That approach is sometimes used when providing templates, and is equivalent to providing the template and implementation all in the header file, but allows humans to read the template declarations without going over the code. Equivalently, if you are providing inlined functions, it would be understandable (not going as far as recommended, but understandable) if you did the same.

For anything else, it is a bad approach. It not only requires all translation units to actually compile all of the function definitions, but it also requires you to declare all functions as inline, or include the header from a single translation, as otherwise it would trigger linker errors.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

This is probably not a mainstream book. Anyway, if we define correctness by the condition of "it compiles", then yes, it is a matter of style, and both styles are correct.

However, the only truly correct style, according to the standard, and design guidelines that match other programming languages, is the first one, matching the spirit of separate compilation of translation units. As you yourself said, the second style would not scale very well.

Another point would be that #include <stdio.h>, which is not standard any more:

#include <cstdio>
Baltasarq
  • 12,014
  • 3
  • 38
  • 57
2

This will certainly work, but it has a couple of downsides:

  • Longer compilation times - normally if you change one file, you only need to compile that one file and the linker will combine it with the other older compilation results. When everything is included into a single file, everything needs to be recompiled at once.
  • Potential namespace collision - any symbols declared in one module are now visible to all of them. This can be a big problem if you use any macros.
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

This is actually a trick I have seen in build systems where for nightly builds to speed them up, including all cpp file in one and them compiling it can generate some big gains in overall speed.

David
  • 3,324
  • 2
  • 27
  • 31