Function overloading, declarations, and namespaces
Organize larger C++ programs with declarations, definitions, overloads, and namespaces.
Learning objectives
- Distinguish a function declaration from its definition.
- Understand function overloading.
- Use namespaces to organize names.
- Understand the role of header and source files.
Prerequisites: understand function declarations, definitions, parameters, return types, and basic header-file use. Review Functions and Header files if needed.
Declaration and definition
A declaration tells the compiler a function's name, return type, and parameter types. A definition provides the function body.
#include <iostream>
int add(int left, int right); // declaration
int add(int left, int right) { // definition
return left + right;
}
int main() {
std::cout << add(2, 3) << '\n';
}A declaration lets code call a function before its definition appears. The linker later needs a matching definition for a function that is used and not otherwise provided.
Function overloading
Functions can share a name when their parameter lists differ. The compiler chooses an overload based on the call's argument types and overload-resolution rules. Return type alone cannot distinguish overloads.
#include <iostream>
int area(int side) {
return side * side;
}
double area(double radius) {
return 3.14159 * radius * radius;
}
int main() {
std::cout << area(4) << '\n';
std::cout << area(4.0) << '\n';
}Namespaces
A namespace groups names and helps avoid collisions. The standard library uses the std namespace, which is why you write std::cout and std::string.
#include <iostream>
namespace geometry {
constexpr double pi = 3.14159;
}
int main() {
double circumference = 2 * geometry::pi * 5;
std::cout << circumference << '\n';
}For beginner projects, prefer qualified names such as std::cout rather than placing using namespace std; in a header. A using-directive in a header can unexpectedly introduce names into every file that includes it.
Header and source files
A common organization is to put declarations in a header such as math.hpp and definitions in a source file such as math.cpp. Include the header where the declarations are needed, then compile and link the source files together. Header guards or #pragma once help prevent repeated inclusion in a translation unit.
One Definition Rule
The One Definition Rule (ODR) describes limits on how many definitions an entity may have across a program. Beginners should avoid putting ordinary non-inline function definitions in headers included by multiple source files, because this can create multiple-definition link errors. Template definitions are commonly placed in headers because the compiler needs their definitions when instantiating them.
Common mistakes
- Assuming a function's return type alone can overload it.
- Declaring a function but never providing its required definition.
- Defining a non-inline function in a header included by several source files.
- Using broad using-directives in shared headers.
Practice
- Overload a function named
printfor int and double values. - Create a namespace for geometry helpers.
- Split a small calculator into a header and source file.
- Explain why a function declaration can appear before its definition.
Practice solutions
Show worked solutions
#include <iostream> void print(int value) { std::cout << "int: " << value << '\n'; } void print(double value) { std::cout << "double: " << value << '\n'; } int main() { print(7); print(3.5); }The parameter types distinguish the overloads; the return type alone would not.#include <iostream> namespace geometry { double square_area(double side) { return side * side; } } int main() { std::cout << geometry::square_area(4.0) << '\n'; }Call it withgeometry::square_area(4.0).- Put
int add(int, int);incalculator.hpp. Put the definition incalculator.cppafter including that header. Include the header frommain.cpp, then compile and link both source files together. Use include guards or#pragma oncein the header. - The declaration tells the compiler the function's interface, so a call can be type-checked before the compiler reaches the definition. The definition supplies the implementation needed by the linker.
Check your understanding
Can two overloads differ only by return type?
Answer: No. The parameter list must distinguish overloads.
Summary
Declarations communicate interfaces, definitions provide implementation, overloads support related operations, and namespaces organize names. Headers and source files help scale a program while respecting the One Definition Rule.