Question
In C++, I have usually used .h files for class declarations and other header content. However, after looking through some Boost library code, I noticed that many headers use the .hpp extension instead.
What are the practical advantages and disadvantages of using .hpp instead of .h for C++ header files?
Short Answer
By the end of this page, you will understand that .h and .hpp are both header file extensions commonly used in C++, but the main difference is convention rather than language behavior. You will learn how compilers and build tools treat header files, why teams choose one extension over another, and how to pick a consistent convention for your own projects.
Concept
In C++, a header file usually contains declarations such as:
- class declarations
- function declarations
- templates
- inline functions
- constants and macros
- include guards or
#pragma once
The key idea is this:
- C++ itself does not require
.hor.hpp - The file extension is mostly a naming convention
- What matters is how the file is included and how your toolchain treats it
For example, these are both valid includes:
#include "person.h"
#include "person.hpp"
The C++ language does not assign different meaning to them. A header named person.h can contain C++ classes, templates, and namespaces. A header named person.hpp can contain the same things.
So why do both exist?
Why teams use different extensions
Historically:
.hhas long been used for C and C++ headers.hppbecame popular as a way to signal "this is specifically a C++ header"
That can be useful in mixed-language codebases where both C and C++ are present.
Why this matters in real programming
The choice affects:
- readability of the project structure
- team consistency
- editor and IDE behavior in some setups
- build scripts or tooling conventions
- whether a project wants to visually separate C headers from C++ headers
In most modern projects, the best choice is not "which extension is technically better," but rather:
- Which convention fits the codebase?
- Will the whole team use it consistently?
A consistent naming style reduces confusion more than the extension itself.
Mental Model
Think of .h and .hpp like two labels on the same type of folder.
- The folder contents are what matter
- The label helps humans understand what to expect
If you label a folder .h, people may think, "general header" or sometimes "possibly C-style header."
If you label it .hpp, people may think, "this is definitely meant for C++."
The compiler, however, mostly cares about the contents and how the file is used, not the label on the folder.
Syntax and Examples
A header file can use either extension.
Example using .h
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
#endif
// main.cpp
#include "math_utils.h"
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
std::cout << add(2, 3) << '\n';
}
Example using .hpp
// math_utils.hpp
#ifndef MATH_UTILS_HPP
#define MATH_UTILS_HPP
int add(int a, int b);
#endif
// main.cpp
#include "math_utils.hpp"
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
std::cout << add(2, 3) << '\n';
}
What changes?
Only the filename and include string change.
The declaration, definition, compilation process, and runtime behavior stay the same.
Common convention patterns
// C-style header in mixed project
#include "logging.h"
// C++-specific header
#include "string_builder.hpp"
Some teams also use:
.hh.hxx.ippfor inline/template implementation fragments
These are conventions, not language rules.
Step by Step Execution
Consider this small example:
// user.hpp
#ifndef USER_HPP
#define USER_HPP
class User {
public:
User(const char* name);
const char* getName() const;
private:
const char* name;
};
#endif
// main.cpp
#include "user.hpp"
#include <iostream>
User::User(const char* name) : name(name) {}
const char* User::getName() const {
return name;
}
int main() {
User user("Ava");
std::cout << user.getName() << '\n';
}
What happens step by step
main.cppincludesuser.hpp- The preprocessor copies the header contents into
main.cpp - The compiler sees the declaration of class
User - The compiler then sees the function definitions for
User::UserandUser::getName - In
main, the program creates aUserobject getName()returns the stored name- The program prints
Ava
Important observation
If user.hpp were renamed to user.h and the include line changed to:
#include "user.h"
the program would behave exactly the same.
That is the core lesson: the extension does not change the C++ semantics.
Real World Use Cases
Here are practical situations where the choice matters.
1. Mixed C and C++ codebases
A project may have:
network.hfor C-compatible declarationsserializer.hppfor C++ classes and templates
This makes the project easier to scan.
2. Library design
Some C++ libraries use .hpp to clearly signal that the headers contain:
- templates
- namespaces
- classes
- overloaded functions
This can be useful for users browsing the API.
3. Legacy systems
Older projects often use .h for everything because that has been a long-standing convention.
4. Build and tooling conventions
Some editors, code generators, or linting setups may group files by extension. A team might choose .hpp if it helps tooling recognize C++ headers more clearly.
5. Team style guides
Many teams pick one rule simply to avoid debates. That is often the most valuable benefit.
Real Codebase Usage
In real projects, developers usually treat this as a style and organization decision.
Common team patterns
Pattern 1: Use .h for all headers
This is common when:
- the codebase is entirely C++
- the team prefers shorter names
- there is no need to distinguish C from C++ headers
Example structure:
include/
user.h
order.h
config.h
src/
user.cpp
order.cpp
Pattern 2: Use .h for C headers and .hpp for C++ headers
This is common when:
- the project mixes C and C++
- a library exposes both C and C++ APIs
- the team wants visual separation
Example structure:
include/
c_api.h
cpp_wrapper.hpp
Pattern 3: Follow the existing ecosystem
If you contribute to an existing project, the normal practice is:
- keep the current naming convention
- avoid renaming files without a strong reason
- prefer consistency over personal preference
Related patterns in real code
Include guards
Regardless of extension, headers should protect against multiple inclusion:
#ifndef CONFIG_HPP
#define CONFIG_HPP
struct Config {
int port;
};
#endif
#pragma once
Many teams use this instead of include guards:
#pragma once
struct Config {
int port;
};
Templates in headers
C++ templates are often fully defined in headers, and these may be named .hpp by convention:
// box.hpp
#pragma once
template <typename T>
class Box {
public:
Box(T value) : value(value) {}
T get() const { return value; }
private:
T value;
};
Again, .h would also work technically.
Common Mistakes
1. Thinking .hpp changes compilation behavior
It usually does not.
Broken assumption:
// This is not automatically "more C++" just because of the extension.
#include "widget.hpp"
The compiler does not give special language meaning to .hpp in normal C++ source inclusion.
2. Mixing conventions randomly
Bad example:
user.h
order.hpp
config.hh
math.hxx
If there is no clear reason, this makes the codebase harder to navigate.
Better approach
Pick one convention and document it.
3. Forgetting to update includes after renaming
Broken code:
#include "person.h"
If the file was renamed to person.hpp, this include will fail.
Fixed version:
#include "person.hpp"
4. Using extension choice as a substitute for proper design
A file named .hpp is not automatically better organized.
You still need:
- clear declarations
- include guards or
#pragma once - minimal includes
- forward declarations when appropriate
5. Assuming all tools treat extensions identically
Most modern tools do, but some build scripts, syntax highlighters, or custom editors may have extension-specific rules. Always check your actual toolchain.
Comparisons
.h vs .hpp
| Aspect | .h | .hpp |
|---|---|---|
| Language meaning in C++ | No special difference | No special difference |
| Common interpretation | General header, sometimes C-style | C++ header |
| Historical usage | Very common | Common in C++ projects |
| Mixed C/C++ projects | Can be ambiguous | Helps signal C++ |
| Brevity | Shorter | Slightly more explicit |
| Team consistency value | High if used consistently | High if used consistently |
Other related extensions
| Extension | Typical use | Notes |
|---|---|---|
.h | General header | Common in both C and C++ |
.hpp | C++ header | Convention only |
.hh | C++ header | Used by some codebases |
.hxx | C++ header | Less common, but valid |
.ipp | Inline/template implementation | Often included from another header |
Which should you choose?
| Situation | Good choice |
|---|---|
Pure C++ project with existing .h files | Keep using .h |
| Mixed C and C++ project | Consider .h for C and .hpp for C++ |
| Contributing to an established codebase | Follow the project convention |
| Starting a new team project | Pick one convention and document it |
Cheat Sheet
Quick facts
.hand.hppare both valid for C++ headers- The extension is mostly a convention
- C++ does not assign different semantics to them
- Consistency matters more than the specific choice
Common meanings
.h= general header.hpp= C++ header
Use .hpp when
- you want to clearly mark files as C++ headers
- your project mixes C and C++
- your team already uses
.hpp
Use .h when
- your codebase already uses
.h - the project is fully C++ and there is no ambiguity
- you prefer the shorter, traditional extension
Always remember
#include "file.h"
#include "file.hpp"
The important difference is the filename, not the C++ language behavior.
Best practice
- choose one convention
- apply it consistently
- use include guards or
#pragma once - follow the existing project style
Red flags
- randomly mixing
.h,.hpp,.hh, and.hxx - renaming headers without updating includes
- assuming extension choice improves code quality by itself
FAQ
Is .hpp required for C++ headers?
No. C++ does not require .hpp. .h works as well.
Is .h only for C and .hpp only for C++?
No. That is a convention some teams use, not a language rule.
Do compilers treat .h and .hpp differently?
Usually not for included headers. The content and build configuration matter more than the extension.
Why do some libraries use .hpp?
Often to clearly signal that the header is intended for C++ and may contain classes, templates, and namespaces.
Should I rename all my .h files to .hpp?
Usually no, unless your team has a clear reason. Renaming creates churn and may break includes or tooling.
What is the best extension for a new C++ project?
There is no single best choice. Pick a convention that fits your project and use it consistently.
Can a .h file contain templates and classes?
Yes. A .h file can contain any valid C++ header content.
What matters more than the extension?
Consistency, good organization, include guards, and clear project conventions matter much more.
Mini Project
Description
Create a small C++ project with a header and source file, then try the same project using both .h and .hpp. This demonstrates that the extension is a convention and helps you practice file organization, includes, and header protection.
Goal
Build a tiny class-based C++ program and verify that it works the same whether the header uses .h or .hpp.
Requirements
- Create a header file that declares a simple class
- Create a
.cppfile that defines the class methods - Include the header from
main.cpp - Add include guards or
#pragma once - Run the program and confirm it behaves the same after renaming the header extension
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.