Separate code into multiple files

Good day.

I have a question about separating code and using header files.

My goal is...


1. Having a layout where most include files are specified only in one place

2.Having my functions and structs in individual files

3. Be able to write functions and structs in any order. For example. as you will see later in my sample code below:
test1() calls test2(), which is defined after test1(). No problem here because they have been declared in header.h.


I read that you usually only have one header file and the rest cpp. But the layout I now have (sample code below) have worked well and fulfills the above(1, 2 & 3) except that in structs.h I would have liked to have a namespace at the top of structs.h that looks like this:
namespace S {map <int, a> my map;}
Which won't work because "struct a" comes after the namespace




project.cpp:

1
2
3
4
5
6
7
8
#include header.h

int main() {

Here I have function calls and some variables
(E.g. myfunction(); var a = 2;)

}






header.h:
Here I have all the include files used by the other files (project.cpp, structs.h, functions.h). (so I don't need to specify the same include files in several places)
E.g.

1
2
3
4
5
6
void test1();
void test2();
#include <iostream>
#include <map>
#include "structs.h"
#include "functions.h" 






structs.h:
Here I have all my structs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct a {

int a = 2;
int b;

a() {
int b = 4;
}

}


struct b {

int z = 22;

}







functions.h:
Here I have all my functions.


1
2
3
4
5
6
7
8
9
10
11
void test1() {

test2();

}

void test2() {

cout << "yo"

}



Last edited on
It's easiest if the headers and source are in the same directory.

The headers usually group stuff that refer to the same subsystem; and so it's normal for structs and prototypes to exist in the same header file.

Of course, it all depends on the size of the project, but it's a good guide as large projects can often be broken into smaller libraries.

One final note, you project headers are included using quotes, not angle brackets as you have done. The preprocessor of the C/C++ languages do not look in the current directories for include files included with "", and it's a hint to programmers that these files are local, and not part of some external library or system include.
It is usually a bad idea to have one include file for all. A lot of unnecessary stuff is included that will or will not be optimized away by the compiler/linker.

I suggest that you include files as they are needed.

namespace S {map <int, a> my map;}
Which won't work because "struct a" comes after the namespace
Is this solved when you include as they are needed or do you have a circular dependency?
The headers are included with quotes, not brackets. I wrote wrong in the example, it's updated now.
By including every header used by any translation unit in all translation units you're guaranteeing you will get the worst possible compilation times. It's the brute force approach of compilation strategies.
First the basics. Never define a function* in a header file. Your functions.h file does. Function declarations go in a header file, but definitions go in a source file. When you are working on a program with a single .cpp file, it doesn't matter, but eventually you will start working on larger programs with multiple source files and you will start running into link errors.

* Exceptions: inline function definitions should usually be in a header file. Template function definitions (which technically aren't functions) should be in a header file. You'll learn about these when you get more experience.

My goal is...


1. Having a layout where most include files are specified only in one place


I'm not sure what you mean. Do you mean having a master header file (like header.h)?

This is counterproductive. For your sample program with 1 or 2 source files, this is fine, but when you start working on projects with hundreds or thousands of files that take minutes or hours to compile, this strategy will come back to bite you. A change to a single header file will cause the entire project to be rebuilt when only a handful of files are really affected. Learning how to do it the correct way now will save you tons of headache down the road.

2.Having my functions and structs in individual files


Usually, each class (or struct in your example) will have one header file and one source file. It is bad practice to define more than 1 class (struct) in a header file unless they are closely coupled (intimately related) to each other. If I have a source file that needs class A but not class B, I don't want to pull in a header that defines both.

I read that you usually only have one header file and the rest cpp.


I think you misunderstood the context of that statement (or else the writer is off his rocker). For a class, 1 header and the rest .cpp. For a project, many header files and many .cpp files.

A more robust file breakdown would be as such:

functions.h
1
2
3
4
5
6
7
#ifndef FUNCTIONS_H
#define FUNCTIONS_H

void test1();
void test2();

#endif 


A.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef A_H
#define A_H

struct A {
    int a = 2;
    int b;

    A() {
        int b = 4;
    }
};

#endif 


B.h
1
2
3
4
5
6
7
8
#ifndef B_H
#define B_H

struct B {
    int z = 22;
};

#endif 


MyMap.h
1
2
3
4
5
6
7
8
9
#ifndef MYMAP_H
#define MYMAP_H

#include "A.h"
#include <map>

namespace S {
    using MyMap = std::map<int, A>;
}


functions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "functions.h"
#include <iostream>

void test1() {

    test2();

}

void test2() {

    std::cout << "yo" << std::endl;

}


project.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "A.h"
#include "B.h"
#include "ByMap.h"
#include "functions.h"

int main() {

    S::MyMap theMap;
    A a;
    B b;
    test1();

}
Last edited on
Thanks you all for your explanations. I dont know how the compiler works, but in the last post/example (by doug) "functions.h" gets included/called two times? If I only have one cpp file, isn't the code below better "technically speaking"? It doesn't look like anything is included more than once at least.


main.cpp:
1
2
3
4
5
#include "functions.h"

int main() {
    test1();
}



functions.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Header.h"

void test1() {

    test2();
    a sd;

}

void test2() {

    std::cout << "yo" << std::endl;

}



Header.h:
1
2
3
4
void test1();
void test2();
#include "structs.h"
#include <iostream> 



structs.h:
1
2
3
4
struct a {
	int ab = 2;
	
};
If I only have one cpp file, isn't the code below better
No. You're putting definitions in a header.
Make up your mind. If you want some functions in one file and other functions in another file then use multiple .cpp files. If you want a single .cpp files then put all the functions there.

I dont know how the compiler works
That's a bit of a problem. Understanding the toolchain from at least a high level perspective is a requirement for C/++ programmers. How do you know your code organization scheme effectively accomplishes what you want if you don't understand what the compiler does?
"Technically speaking" it's much worse.

There is NOTHING WRONG with including a header file in multiple locations. As a matter of fact, you want that. Let me make this clear. The purpose of header files is to allow declarations to be included multiple times in your code separate from the definitions of the functions. You WANT to include header files into multiple source files. Trying to reduce the number of times a particular header file is included is WRONG!

The header file provides a contract between the the function (in this case) and the user of the function. The header tells us that there will be a function "test1" which takes no arguments and has a void return. The writer of the function and the caller of the function both need to know what test1 is supposed to do. So, both source files (functions.cpp and project.cpp in my example) require knowledge of that function.

If you define tes1() inside a header file (like you did again in your last post even after I told you not to), it will lead to link errors.

If you have 2 source files, both of which include functions.h, you will end up with 2 difinitions of test1() and test2() in your compiled objects, and the linker won't know how to link the final executable. Again, with your little toy program with 1 source file it will work, but add a second source file and it won't link properly.
No. You're putting definitions in a header.
Make up your mind. If you want some functions in one file and other functions in another file then use multiple .cpp files. If you want a single .cpp files then put all the functions there.


Here you just sound like you're following rules without knowing why. I know that's the recommended way to it, but I want to understand why. (Dougs explanation helped).

That's a bit of a problem. Understanding the toolchain from at least a high level perspective is a requirement for C/++ programmers. How do you know your code organization scheme effectively accomplishes what you want if you don't understand what the compiler does?


You're right, I need to dive deeper into this.
Here you just sound like you're following rules without knowing why.
It's the same reason people gravitate to only a few coding and naming styles: convention. People expect that a header can be included from multiple translation units without causing errors. By going against convention all you accomplish is confusing your colleagues.
Great stuff.

How about the namespace. Why can a class definition (in header) be included multiple times without problem , but not a namespace? Is it because the class is just a definition/future instructions and not an object yet?
Can you show an example of what you mean?
I tried to have a namespace:

namespace x {
int a = 20;
}

... in a header together with some class definitions. This file gets included from different cpp files that needs access to the classes. The program works without the namespace in that header file
Show us what you mean. Your statement is a little bit too vague and open to interpretation.

header.h
1
2
3
4
5
6
7
struct a {
    int ab = 2;
};

namespace x {
    int z = 23;
}


main.cpp and functions.cpp includes header.h. They need access to a::ab. I moved the namespace to its own file so I can include it only from main.cpp... But i'm still curious why the classes can be included twice but not the namespace
Last edited on
Do you know the difference between a declaration and a definition?

Header files should only contain declarations, definitions belong in source files.

In your above code you have a structure declaration and an int variable definition (contained within a namespace). Instead of defining the variable you should be declaring the variable with the extern qualifier.

1
2
3
namespace x {
    extern int z;
}


Then in some source file you need to define that global variable inside the namespace.

1
2
3
namespace x {
   int z = 23;
}


What @jlb said.

Also, namespaces inherently span multiple files. The following is no problem

hdr1.h
1
2
3
4
5
6
7
#ifndef HDR1_H
#define HDR1_h
namespace X
{
    struct MyStruct1 { int x = 0; };
}
#endif 


hdr2.h
1
2
3
4
5
6
7
#ifndef HDR2_H
#define HDR2_h
namespace X
{
    struct MyStruct2 { int x = 4; };
}
#endif 


main.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "hdr1.h"
#include "hdr2.h"

int main()
{
    X::MyStruct1 ms1;
    X::MyStruct2 ms2;

    ms1.x = 10;
    ms2.x = 20;
}


Namespaces are essentially just extensions to the names of the types and objects they contain. So, just like you can define class Module1_CoreClass and class Module2_CoreClass in separate files, similarly you can define class Module1::CoreClass and class Module2::CoreClass in separate files. The compiler knows under-the-hood that these classes share a namespace and everything is worked out.
Topic archived. No new replies allowed.