C++ PROGRAMMING ยท 14 MIN STUDY

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.

C++17
#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

  1. Overload a function named print for int and double values.
  2. Create a namespace for geometry helpers.
  3. Split a small calculator into a header and source file.
  4. Explain why a function declaration can appear before its definition.

Practice solutions

Show worked solutions
  1. #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.
  2. #include <iostream>
    
    namespace geometry {
        double square_area(double side) {
            return side * side;
        }
    }
    
    int main() {
        std::cout << geometry::square_area(4.0) << '\n';
    }
    Call it with geometry::square_area(4.0).
  3. Put int add(int, int); in calculator.hpp. Put the definition in calculator.cpp after including that header. Include the header from main.cpp, then compile and link both source files together. Use include guards or #pragma once in the header.
  4. 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.

References