Search

1.9 — Header files

Headers, and their purpose

As programs grow larger and larger (and include more files), it becomes increasingly tedious to have to forward declare every function you want to use that lives in a different file. Wouldn’t it be nice if you could put all your declarations in one place?

C++ code files (with a .cpp extension) are not the only files commonly seen in C++ programs. The other type of file is called a header file, sometimes known as an include file. Header files usually have a .h extension, but you will sometimes see them with a .hpp extension or no extension at all. The purpose of a header file is to hold declarations for other files to use.

Using standard library header files

Consider the following program:

This program prints “Hello, world!” to the console using cout. However, this program never defines cout, so how does the compiler know what cout is? The answer is that cout has been declared in a header file called “iostream”. When we use the line #include <iostream>, we’re requesting that all of the content from the header file named “iostream” be copied into the including file. That makes the content from the header file available for use in our code file.

Keep in mind that header files typically only contain declarations. They do not define how something is implemented. So if cout is only declared in the “iostream” header file, where is it actually defined? It is implemented in the C++ runtime support library, which is automatically linked into your program during the link phase.

Consider what would happen if the iostream header did not exist. Wherever you used std::cout, you would have to manually copy in all of the declarations related to std::cout into the top of each file that used it! This would require knowledge of what’s relevant and what’s not. It’s much easier to just #include iostream!

Writing your own header files

Now let’s go back to the example we were discussing in a previous lesson. When we left off, we had two files, add.cpp and main.cpp, that looked like this:

add.cpp:

main.cpp:

(If you’re recreating this example from scratch, don’t forget to add add.cpp to your project so it gets compiled in).

We used a forward declaration so that the compiler would know what “add” was when compiling main.cpp. As previously mentioned, writing forward declarations for every function you want to use that lives in another file can get tedious quickly.

Header files can relieve us of this burden. A header file only has to be written once, and it can be included in as many files as needed. This also helps with maintenance by minimizing the number of changes that need to be made if a function prototype ever changes (eg. by adding a new parameter).

Writing our own header files is surprisingly easy. Header files consist of two parts.

The first part is called a header guard, which is discussed in the next lesson (on the preprocessor). Header guards prevent a given header file from being #included more than once in the same file.

The second part is the actual content of the .h file, which should be the declarations for all of the functions we want other files to be able to see. Our header files should all have a .h extension, so we’ll call our new header file add.h:

add.h:

In order to use this header file in main.cpp, we have to include it.

main.cpp that includes add.h:

add.cpp stays the same:

When the compiler compiles the #include "add.h" line, it copies the contents of add.h into the current file at that point. Because our add.h contains a function prototype for add(), this prototype is now being used as a forward declaration of add()!

Consequently, our program will compile and link correctly.

Note: When you #include a file, the entire content of the included file is inserted at the point of inclusion.

If you get a compiler error about add.h not being found, make sure the file is really named add.h. Depending on how you created and named it, it’s possible the file could have been named something like “add” (no extension) or “add.h.txt” or “add.hpp”.

If you get a linker error about add() not being defined, make sure you’ve included add.cpp in your project so it compiles properly!

Angled brackets vs quotes

You’re probably curious why we use angled brackets for iostream, and double quotes for add.h. The answer is that angled brackets are used to tell the compiler that we are including a header file that was included with the compiler, so it should look for that header file in the system directories. The double-quotes tell the compiler that this is a header file we are supplying, so it should look for that header file in the current directory containing our source code first. If it doesn’t find the header file there, it will check any other include paths that you’ve specified as part of your compiler/IDE settings. That failing, it will fall back to checking the system directories.

Rule: Use angled brackets to include header files that come with the compiler. Use double quotes to include any other header files.

Header files may include other header files. However, you should never rely on this. Always #include all of the header files you need to use from each .cpp file.

Rule: Each .cpp file should explicitly #include all of the header files it needs to compile.

Why doesn’t iostream have a .h extension?

Another commonly asked question is “why doesn’t iostream (or any of the other standard library header files) have a .h extension?”. The answer is, because iostream.h is a different header file than iostream is! To explain requires a very short history lesson.

When C++ was first created, all of the files in the standard runtime library ended in .h. Life was consistent, and it was good. The original version of cout and cin lived in iostream.h. When the language was standardized by the ANSI committee, they decided to move all of the functions in the runtime library into the std namespace (which is generally a good idea). However, this presented a problem: if they moved all the functions into the std namespace, none of the old programs would work any more!

To try to get around this issue and provide backwards compatibility for older programs, a new set of header files was introduced that use the same names but lack the .h extension. These new header files have all their functionality inside the std namespace. This way, older programs that include #include <iostream.h> do not need to be rewritten, and newer programs can #include <iostream>.

When you include a header file from the standard library, make sure you use the non .h version if it exists. Otherwise you will be using a deprecated version of the header that is no longer supported.

In addition, many of the libraries inherited from C that were still useful in C++ were given a c prefix (e.g. stdlib.h became cstdlib). The functionality from these libraries was also moved into the std namespace to help avoid naming collisions.

However, when you write your own header files, you should give them all a .h extension, since you will not be putting your code in the std namespace.

Rule: use the non .h version of a library if it exists, and access the functionality through the std namespace. If the non .h version does not exist, or you are creating your own headers, use the .h version

Including header files from other directories

Another common question involves how to include header files from other directories.

One (bad) way to do this is to include a relative path to the header file you want to include as part of the #include line. For example:

The downside of this approach is that it requires you to reflect your directory structure in your code. If you ever update your directory structure, your code won’t work any more.

A better method is to tell your compiler or IDE that you have a bunch of header files in some other location, so that it will look there when it can’t find them in the current directory. This can generally be done by setting an “include path” or “search directory” in your IDE project settings.

In Visual Studio, you can right click on your project in the Solution Explorer, and choose “Properties”, then the “VC++ Directories” tab. From here, you will see a line called “Include Directories”. Add your include directories there.

In Code::Blocks, go to the Project menu and select “Build Options”, then the “Search directories” tab. Add your include directories there.

Using g++, you can use the -I option to specify an alternate include directory.

The nice thing about this approach is that if you ever change your directory structure, you only have to change a single compiler or IDE setting instead of every code file.

Can I put function or variable definitions in a header file?

You shouldn’t, as it may cause linker errors. We’ll explain why in the upcoming lesson on header guards.

Declarations are okay.

Header file best practices

Here are a few best practices for creating your own header files.

  • Always include header guards.
  • Do not define variables in header files unless they are constants. Header files should generally only be used for declarations.
  • Do not define functions in header files.
  • Each header file should have a specific job, and be as independent as possible. For example, you might put all your declarations related to functionality A in A.h and all your declarations related to functionality B in B.h. That way if you only care about A later, you can just include A.h and not get any of the stuff related to B.
  • Give your header files the same name as the source files they’re associated with (e.g. grades.h goes with grades.cpp).
  • Try to minimize the number of other header files you #include in your header files. Only #include what is necessary.
  • Do not #include .cpp files.
1.10 -- A first look at the preprocessor
Index
1.8a -- Naming conflicts and the std namespace

414 comments to 1.9 — Header files

  • hypost

    Great pics!Your tutorials really make my life much easier!

  • Rajsekar

    i named my header file add.h, if i mention this in main like #include "add.h"
    it says "no such file or directory found"...if i see in properties the header name is "../add.h",if i put this name the program compiles but if i use only "add.h" it dosen't...
    someone help me please...I use codeblocks

    • nascardriver

      Hi Rajsekar!

      Sounds like @add.h is in the wrong directory. Make sure it's in the same directory as @main.cpp.

      • Rajsekar

        thank u nascar..i saved that in other directory..now i corrected it, it works fine...

        if i add an empty file and defined functions in that instead of a "source file" it doesn't compile...Y?

  • Me

    I'm having issues with my code (visual studio).
    I have Main.cpp which contains

    I have NewFile.cpp which contains

    and I have NewFile.h which contains

    This is the error I'm getting in the output:
    1>------ Build started: Project: HelloWorld, Configuration: Debug Win32 ------
    1>NewFile.h
    1>Debug\NewFile.obj : warning LNK4042: object specified more than once; extras ignored
    1>HelloWorld.obj : error LNK2019: unresolved external symbol "int __cdecl doubleNumber(int)" (?doubleNumber@@YAHH@Z) referenced in function _main
    1>C:\Users\noahp\source\repos\HelloWorld\Debug\HelloWorld.exe : fatal error LNK1120: 1 unresolved externals
    1>Done building project "HelloWorld.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    What's going wrong here? Thanks.

    • Dima

      Try to add "#pragma once" at the end of "NewFile.h". I've tested your code with this change and it worked.

    • Brian Gaucher

      I think it's because you included a header file inside your header file.

      Main.cpp

      Newfile.h

      You end up include'ing' "stafx.h" twice which is redundant. So it warns you

  • himanshu

    HI Alex!
    Here i need your help please reply.
    I totally confused what we do after
    creating a directory.
    for example you created a directory using g++
    and then what !
    what is the uses of this directory.

    • nascardriver

      Hi himanshu!

      g++ doesn't create a directory, you create it and tell g++ where it is.

      This directory contains header files which you can then include from your other files.

      main.cpp

      [../src/source/] g++ -I ../includes/ apple.cpp main.cpp

      The "-I ../includes/" allows all files to include files that are located in src/includes/.

      • himanshu

        hi
        i does not understand what  you are try to say
        but can we create our own directory

        • Alex

          You can, but you don't need to. And unless you have a specific reason to do so, you probably shouldn't. 🙂

          • himanshu

            Hi!
            Alex

            GOOD MORNING!

            I think you had explained to how to create our own directory.

            But please answer my this question as simple as you can.

            I totally confused what we do after
            creating a directory.
            for example you created a directory using g++ and then how can we call it or its components that it contains.

            AND ONE BONUS QUESTION:

            Difference between header file and directory.

            • Alex

              I don't explain how to create a directory anywhere (how to do so depends on your operating system, not g++). The directories mentioned in the g++ example are using directories that have already been created, not creating them.

              A header file is a C++ file that contains declarations. A directory is a container that is part of a heirarchical file system. See https://www.computerhope.com/jargon/d/director.htm

  • Ishak

    #include <iostream.h> does this include the function definition? I'm confused. what did they move from <iosteam.h> to std namespace that made <iostream.h> not usable? why couldnt they use namespace std on old programs??

    • Ishak

      Also C++ runtime support library, is that namespace std? or am I confusing stuff?

    • Alex

      > #include does this include the function definition?

      Typically not, the definitions are typically only provided as a precompiled library file, which gets linked into your program.

      > what did they move from to std namespace that made not usable?

      All of the declarations were moved from outside the std namespace to inside the standard namespace. This means any code using iostream.h would not work with iostream, as the code doesn't use the std:: prefix as required to access those declarations inside the namespace.

      > why couldnt they use namespace std on old programs??

      You could, but the point of the name change was to make it so you could still compile older programs without having to modify them first.

  • Hema

    In the above example of add.h, add.cpp and main.cpp, is the scope X and Y restricted to add.cpp or are they accessible in main.cpp also?

    • nascardriver

      Hi Hema!

      @x and @y are parameters of @add. They are set by the caller and can only be accessed by @add.
      In the above example @x will be set to 3 and @y will be set to 4, after that only @add can read and change those variables. They disappear when @add returns.
      Function parameters are covered in lesson 1.4a.

  • omar

    hello
    my question what is the main function of header file #include "stdafx.h" ...why we use it? is there any alternative way for it?

  • nascardriver

    Hi Alex!

    I ran into something here and I'm confused whether this is a feature of C++ or a compiler problem.

    other.hpp

    main.cpp

    Now, naturally I'd say this doesn't work. The syntax is all messed up. But it does work. I understand why it works but I can't imagine it's supposed to.
    Tested with g++ and msvc++.
    Removing the closing bracket in main.cpp will cause a compiler error in main.cpp when using g++ or in other.hpp when using msvc++.
    I didn't test things other than a namespace, I guess they behave the same.
    Please tell me this isn't legal C++.

    • Alex

      It's syntactically legal, though rather idiotic. 🙂 Header files don't get compiled directly, they only get compiled when they are included into a .cpp file. So when main.cpp #includes other.hpp, the contents of other.hpp are copied into main.cpp at the point of inclusion (by the preprocessor). Then _that_ is compiled. The compiler has no idea that the closing brace in main.cpp was ever disconnected from the namespace in other.hpp...

      That said, you should never do this. 🙂

Leave a Comment

Put all code inside code tags: [code]your code here[/code]