What hides behind the words "declaration" and "definition"?
Imagine you are building a huge skyscraper. You have a blueprint (declaration) and you have an actual concrete column (definition). Without the blueprint, you don't know what the column should be. Without the column, the building collapses. In C++, it's exactly the same story, but with one important nuance: if you make a mistake, it's not the building that collapses, but your program — with a compilation or linking error.
The question "What is the difference between a definition and a declaration?" has remained one of the most popular on Stack Overflow for many years. And for good reason. Even experienced developers sometimes get confused, especially when it comes to extern, static, or templates. In 2025, with the growing complexity of projects and the use of C++20 modules, understanding this difference becomes a critical skill.
In this article, we won't just give a dry definition. We'll break down live code, show the "pitfalls" that beginners stumble into, and provide best practices that will save you hours of debugging.
Declaration is a promise to the compiler
Declaration is a way to tell the compiler: "Hey, listen, this thing exists! It has a name and a type, but where it lives and what it looks like is still a secret."
In simple terms: a declaration introduces a name into the program. It does not allocate memory, create an object, or write function code. It simply tells the compiler: "Trust me, this exists, use it."
Here is what a pure function declaration looks like in C++:
// Declaration of a functionint calculateSum(int a, int b);
// Declaration of an external variableextern int globalCounter;Notice the keyword extern for the variable. Without it, this would be a definition. For functions, the keyword is not needed — if there is a semicolon after the signature, it is a declaration.
Why are declarations needed?
- Forward declaration. Allows you to use a function before the compiler sees its body. A classic example is two classes that reference each other.
- Splitting into .h and .cpp. In header files, we write declarations; in implementation files, we write definitions. This is the foundation of modularity.
- Speeding up compilation. The compiler doesn't need to parse huge function bodies every time — signatures are enough.
Definition is reality
Definition is when the compiler finally allocates memory or generates code. It is the fulfillment of the promise.
For a function, a definition is the function body. For a variable, it is memory allocation. For a class, it is a complete description of all its members.
// Definition of a functionint calculateSum(int a, int b) { return a + b;}
// Definition of a variableint globalCounter = 0; // Without extern — this is a definition!
// Definition of a classclass MyClass {public: void doSomething() {} // Method definition inside the class};The One Definition Rule (ODR)
This is the most important rule you must remember. ODR states: throughout the entire program, there can be only one definition of each entity (function, variable, class).
But there can be any number of declarations! That's why in header files we write declarations, and in .cpp files we write the single definition. Violating ODR leads to a linker error — the most unpleasant kind, because it occurs after compilation.
In 2025, with the widespread adoption of C++20 and modules, ODR has become easier to follow. But the classic model with header files hasn't gone away, and understanding it is essential.