As a program grows you need to split it across files, keep names from colliding, and pull in third-party libraries. In C++ that job has traditionally been shared by three things: header and source files, namespaces, and the build system. This chapter covers that classic setup, then looks at CMake targets, package managers, and where C++20 modules fit in.
Headers and source files
The usual convention is to put declarations in a header (.h or .hpp) and definitions in a source file (.cpp). Other files #include the header to learn what exists; the linker later connects the calls to the actual code.
// math_utils.hpp
#pragma once
namespace mathx {
int gcd(int a, int b);
double mean(const int* values, int count);
}
// math_utils.cpp
#include "math_utils.hpp"
namespace mathx {
int gcd(int a, int b) {
while (b != 0) {
int t = a % b;
a = b;
b = t;
}
return a;
}
double mean(const int* values, int count) {
if (count == 0) return 0.0;
long long sum = 0;
for (int i = 0; i < count; ++i) sum += values[i];
return static_cast<double>(sum) / count;
}
}
#pragma once keeps a header from being processed twice in the same translation unit. It isn't part of the standard, but every mainstream compiler supports it; the portable alternative is a classic #ifndef/#define include guard.
Separate compilation
Each .cpp file is compiled on its own into an object file, and the linker stitches the object files together. Change one source file and only that file needs recompiling.
g++ -std=c++20 -c math_utils.cpp -o math_utils.o
g++ -std=c++20 -c main.cpp -o main.o
g++ main.o math_utils.o -o app
Two linker errors come up constantly. "Undefined reference" means something was declared and used but never defined in any object file you linked. "Multiple definition" usually means a function body lives in a header that several source files include. If you really want a function defined in a header, mark it inline, or make it a template or a member function defined inside the class body.
Namespaces
Namespaces group names under a common prefix so that libraries don't trip over each other. Everything in the standard library lives in std.
#include <iostream>
#include "math_utils.hpp"
namespace app::config { // C++17 nested namespace syntax
constexpr int retries = 3;
}
int main() {
std::cout << mathx::gcd(12, 18) << '\n'; // 6
std::cout << app::config::retries << '\n';
using mathx::gcd; // bring in just this name
std::cout << gcd(8, 12) << '\n';
}
Never write using namespace std; in a header: it leaks every standard name into every file that includes yours. Inside a source file, importing a few specific names with in a narrow scope is the safer habit.
0 条评论
登录 · 登录后即可发表评论。