Declaration tells the compiler a name exists. Definition creates the actual thing the name refers to.
Mixing the two up leads to linker errors, runtime crashes, and hours of head-scratching. Master the distinction once and your code becomes clearer, faster to build, and safer to maintain.
Core Distinction in One Breath
A declaration is a promise; a definition is the delivery.
The compiler only needs the promise to compile a file. The linker needs the delivery to connect all files into a runnable program.
Keep this mental picture: declaration is the table of contents, definition is the full chapter.
Variables: The First Split
Declaration Without Definition
Prefixing extern before a variable creates a declaration.
Example: extern int counter; tells every file that includes this line, “Somewhere there is an int named counter; trust me.”
Definition in One File
Drop the extern and you get the definition: int counter = 0;.
Exactly one source file must contain this line so the linker finds one unique place in memory.
One-Definition Rule Safety
Put the extern line in a header, the plain definition in a single .cpp file.
Include the header everywhere you need the variable; the linker will merge references to the single definition.
Functions: Prototype vs Body
Prototype as Declaration
double area(double r); is a prototype.
It announces the function’s signature so other code can call it.
Body as Definition
The same line with braces becomes the definition: double area(double r){ return 3.14*r*r; }.
Only one definition may exist across the entire build; multiple prototypes are harmless.
Inline Exception
Marking a function inline allows its body in a header.
The compiler merges duplicate bodies into a single copy, so you can break the one-definition rule safely.
Classes and Structs: Special Rules
Forward Declaration
class Node; lets you declare pointers or references to Node before the full class is seen.
This speeds up compilation by reducing header churn.
Member Function Split
Declare methods inside the class body, define them in a .cpp file to hide implementation.
This keeps headers slim and rebuild times low.
Template Twist
Template functions and classes must be defined in every translation unit that uses them.
Put the full code in the header; the compiler generates specializations on demand.
Header Guards and Redundancy
Include-Once Pattern
Wrap headers in #ifndef HEADER_H / #define HEADER_H / #endif.
This prevents multiple declarations from causing redefinition errors.
Pragma Once Alternative
#pragma once is shorter and widely supported.
Either technique keeps declarations idempotent.
Storage Duration Illustrated
Static Variables
Declaration extern int shared; in a header pairs with definition int shared = 10; in one .cpp.
The single object lives for the whole program run.
Automatic Variables
Inside a function, int x = 5; is always a definition.
No extern is allowed here; storage is created each time the block runs.
Linkage and Visibility
Internal Linkage
Prefixing a variable with static at file scope makes it internal.
Each translation unit gets its own copy, invisible to others.
External Linkage
Omitting static gives external linkage, so the name can tie to a single definition elsewhere.
Use this to share globals across files cautiously.
Common Pitfalls
Multiple Definitions
Placing int value = 0; in a header included by two .cpp files triggers a linker error.
Remember: headers are pasted into every includer.
Missing Definition
Declaring extern int value; everywhere but forgetting to define it somewhere yields an unresolved symbol.
The linker cannot find the promised object.
Order Dependence
Calling a function before its prototype is seen makes the compiler assume old C rules, often breaking C++ type safety.
Always provide a declaration before use.
Best-Practice Cheat Sheet
For Globals
Header: extern int g_max;
Source: int g_max = 100;
For Functions
Header: void log(const std::string& msg);
Source: implement the body.
For Classes
Header: class declaration with inline tiny methods.
Source: definitions for large or non-template methods.
Quick Diagnostic Tips
Linker errors about “multiple definitions” almost always mean a variable definition landed in a header.
“Undefined reference” means you declared but never defined the entity.
When in doubt, add extern to the header and move the initializer to a single .cpp file.