1

Suppose I have a program that's like

#include <iostream>
#include <algorithm>

class HelloWorlder
{
public: 
  HelloWorld();
  ~HelloWorld();
  void print_content() {std::cout << "Hello, world!"};
};

class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}

};

int main()
{
    HelloWorlder HW;
    HW.print_content();

    StringReverser SR;
    SR.reverse_and_print("Jon Skeet");

    return 0;
}

Then am I supposed to partition those into files main.cpp, HelloWorlder.h, HelloWorlder.cpp, StringReverser.h and StringReverser.cpp; or do I just use a main.cpp, one .h and one .cpp? If the former, then how do I link the files together if one of the classes uses another? For instance, if I changed the second class to

class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}
private:
  HelloWorlder h;
}

then do I have to do something like

StringReverser.cpp

#include "StringReverser.h"
#include "HelloWorlder.h"

class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}
private:
  HelloWorlder h;
}

or is there some other thing I have to do as well?

5 Answers5

1

Putting class into separated source and header files is not required by the language, but generally it make a cleaner and isolated scope, and is recommended in most situation.

Check for the scope definition of the language, especially the class scope and file(compilation unit) scope.

Non-maskable Interrupt
  • 3,841
  • 1
  • 19
  • 26
1

No one's forcing you to, but it's recommended to do as you say: partition those classes into their own .cpp/.h files (or at least I'd recommend it).

This question right here shows how to link .cpp files together.

Community
  • 1
  • 1
not satan
  • 142
  • 8
1

You don't need to put each class in its own file in C++. But, you can do it if you want to, and it is generally recommended to do so.

How you link them depends on which platform you are in? If you are in Windows, and you have Visual Studio you just need to pick Run or Debug from the Debug Menu (This may depend on the version you are using, so check against your particular version). If you are on Linux, a short tutorial on gcc like this one will help you.

dev_nut
  • 2,476
  • 4
  • 29
  • 49
1

It is conventional; both practices are used : small C++ files with one file per class, or large C++ files with several related classes and functions.

I don't recommend putting in C++ each class in its separate source and header file (this is nearly required by Java, not in C++). I believe that a class belongs conceptually to some "module" (and often a "module" contains several related classes and functions).

So I suggest declaring related classes of the same "module" in the same header file (e.g. foo.hh), and implementing these classes in related (or same) code files (e.g. one foo.cc or several foo-bar.cc & foo-clu.cc & foo-dee.cc), each of them #include-ing foo.hh

You usually want to avoid very short C++ files (to avoid huge build time). So I prefer having code files of several thousand lines, and header files of several hundred lines. In small sized applications (e.g. less than 30 thousand lines of code), I might have a single common header file. And a "module" (currently this is only a design, no C++11 feature explicitly supports modules) is often made of several related classes and functions. So I find that a source file implementing a "module" with several classes is more readable & maintainable than several tiny source files.

There is a reason to avoid very short source code files (e.g. of a hundred lines of code). Your C++ program will use standard C++ template containers, so will #include -directly or indirectly- several standard headers like <string>, <vector>, <map>, <set>, etc.... In practice, these headers may bring thousands of lines (which the compiler will parse). For instance including both <vector> and <map> brings 41130 lines on my GCC 4.9. So a source file of a hundred lines including just these two headers takes a significant amount of time to be compiled (and you generally need to include standard containers in your header file). Hence a program with ten source files of a few thousands lines each will build faster than the same program organized in hundreds of source files of a few hundred lines each. Look into the preprocessed form of your code obtained using g++ -Wall -C -E !

Future versions of C++ might have proper modules (the C++ standardization committee has and will discuss that, see e.g. n4047). Today C++11 don't have them, so I quoted "modules". Some languages (Go, Rust, Ocaml, Ada, ...) already have proper modules. And a module is generally made of several related classes, types, functions, variables.

Some C++ compilers are able to pre-compile header files. But this is compiler specific. With g++ it works well only if you have one single common header file. See this answer.

BTW, you should look into existing free software C++ code. Some projects have lots of small files, others have fewer but larger files. Both approaches are used!

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    *"You usually want to avoid very short C++ files."* This seems completely counter-intuitive and I usually find people recommending the exact opposite. I would be interested in your reasoning. – cdhowie Nov 16 '14 at 07:31
  • I explained my reasoning. You want to avoid huge compilation times. – Basile Starynkevitch Nov 16 '14 at 07:33
  • I am not a fan of sacrificing maintainability to gain a performance advantage during compilation. Parallel compilation, precompiled headers, and modern disks (such as SSDs) all go a long way to making this rationale obsolete. Of course I understand that there are cases when these are not options, but in general I would not recommend a programming style geared toward what is fast becoming the corner case. – cdhowie Nov 16 '14 at 07:41
  • Two more things: (1) I totally missed your explanation the first time I read the question, even though it's super obviously *half of your answer* (my bad!) and (2) this is why I voted to close as opinion-based. ;) – cdhowie Nov 16 '14 at 07:45
  • Putting in a single "module" (I use quotes, since C++ does not have proper modules yet) some related classes & functions in a single (or few) source files *increases maintainability* – Basile Starynkevitch Nov 16 '14 at 07:46
  • If you have long build time you should improve abstraction (one way is isolate class into multiple files so each compilation unit take shorter) and then use the dependency file supported by most compiler to avoid unnecessary compiles. – Non-maskable Interrupt Nov 16 '14 at 15:30
  • I don't buy that argument. Having `std::map>` is a natural thing. And that means 41KLOC of included code at least (from ``,``, ``). No abstraction can avoid that. – Basile Starynkevitch Nov 16 '14 at 15:46
1

In addition to the other questions, there's also some performance gain in separation. If you have 5 classes each with their own header files, but a .cpp file only uses two of the classes, then it makes sense to only load those two headers. The compiler will have to crunch less code as opposed to loading one header with all five class definitions. For a small project this isn't a big deal, but as you begin to add hundreds of classes to your code, being selective can have its performance perks.

This can be expanded further into using function and class prototypes instead of entire class files, but for the sake of your question, class isolation in separate header files is a good start in gaining both performance and organization of your code.

To answer the other part of your question, if your project is setup correctly, the compiler will automatically compile every .cpp referenced in it. The headers are a different story. So long as your .cpp files reference only the headers they need, your code should compile fine. At first, this may seem a bit difficult to manage, but after some practice you'll get good at it and find your code hierarchy to be easy to navigate and understand.

David Peterson
  • 728
  • 6
  • 17