Módulos, Pacotes e Importação em C++: Guia Detalhado
What is it and why? (a real-life analogy)
Imagine you are writing a huge 100-page essay. If you write it in one file, you will very quickly get confused: where is your introduction, where is the main part, and where is the conclusion. Scrolling back and forth is terribly inconvenient. It is much smarter to break the essay into separate chapters: "Chapter 1: Introduction", "Chapter 2: Main Body", "Chapter 3: Conclusion". Each chapter can be written in a separate document, and then you can simply put them together.
The same thing happens in programming. When a program becomes large (for example, a game, a calculator, or a website), storing all the code in one file is a bad idea. This is called a "monolith," and it is difficult to work with: it's hard to find errors, hard to change anything, and hard to understand what is where.
Modules and packages are a way to break a large program into small, independent pieces. Each piece (module) does its own thing: one module handles graphics, another handles sound, and a third handles mathematical calculations. And import is a command that tells the program: "Take this piece from another file and use it here."
💡 Simple analogy: Imagine you are assembling a Lego set. You have boxes with different parts: wheels, bricks, windows. Each box is a module. When you need a wheel, you don't dig into the box with windows — you take it from the box with wheels. Import is when you say: "Give me the wheels from box #3."
In C++, until recently, there were no proper modules (they only appeared in the C++20 standard). Instead, programmers used header files (files with the extension .h or .hpp) and source code files (.cpp). This worked, but it was inconvenient. Now we will look at both approaches: the classic one (via header files) and the modern one (via C++20 modules).
Theory: how it works internally
Let's look "under the hood" and understand what happens when you write #include or import.
Classic approach: header files
Imagine you have two files: main.cpp (the main program) and math_utils.cpp (useful mathematical functions). The C++ compiler processes each .cpp file separately. It doesn't know what exists in other files. Therefore, if in main.cpp you want to call the function sum(2, 3), which is written in math_utils.cpp, the compiler will say: "I don't know such a function!".
To solve this problem, header files were invented. These are files where you write declarations of functions, classes, and variables, but not their implementation. A declaration is like a "business card": it tells the compiler that the function exists, what its parameters are, and what it returns. The implementation (definition) lies in the .cpp file.
When you write #include "math_utils.h", the compiler literally inserts the contents of that file into your main.cpp. Now it "sees" the function declaration and doesn't complain. And at the build stage (linking), all the pieces are connected into one program.
⚠️ Important: #include is not a C++ language command, but a preprocessor directive. The preprocessor works before compilation and simply copies the text. It's like copying text from one document to another.
Modern approach: C++20 modules
Starting from C++20, the language has real modules. They work differently. A module is not just text copying, but a full-fledged compilation unit. A module can export (make visible) only what you want to show, and hide internal details.
Advantages of modules:
- Compilation speed: The compiler doesn't copy huge header files every time. It compiles the module once and remembers the result.
- Isolation: Extra macros or variables that could break your code won't accidentally "leak out" of a module.
- Cleanliness: You don't need to write
#includein a specific order. Modules don't depend on the order of inclusion.
Module syntax:
// math_utils.cpp (now this is a module file)
export module math_utils; // Declares that this is a module named math_utils
export int sum(int a, int b) { // export makes the function visible externally
return a + b;
}
// Internal function — it will not be visible outside the module
int helper() {
return 42;
}
Using the module:
// main.cpp
import math_utils; // Import the module
int main() {
int result = sum(2, 3); // Works!
// int x = helper(); // Error! helper is not exported
return 0;
}
💡 Note: Modules are a new feature. Not all compilers support them 100%. If you are using an old compiler (e.g., Visual Studio 2019 or GCC 10), modules might not work. In that case, use the classic approach with header files.
Syntax in C++: all forms and variants
Let's go over all possible ways to include external code in C++.
1. The #include directive
This is the oldest and most common method. It comes in two types:
| Form | Syntax | Where it looks for the file | Example |
|---|---|---|---|
| Angle brackets | #include <name> |
In the compiler's system folders (standard library) | #include <iostream> |
| Quotes | #incl |