← Back to C++ Course | Chapter 16: Modern C++ | Lesson 8 of 9

C++ Modules (C++20)

Modules are a newer way to split code into pieces and share it, like separate labeled chapters you can import. They are cleaner than the old header files.
Syntax
cpp
export module module_name;

export return_type function_name(parameters) { }

// in another file
import module_name;

Understanding Modular Design

C++20 Modules are a modern replacement for the traditional #include header system, designed to speed up compilation and give each file explicit, isolated control over what it exposes to the rest of the program.

Example: Understanding Modular Design

cpp
// math.cppm -- a C++20 module file
export module math;

export int add(int a, int b) {
	return a + b;
}

// main.cpp would then say: import math;  add(2, 3);

Why Modules are Better than Headers

Traditional headers rely on the preprocessor literally copy-pasting their entire contents into every file that includes them, which means the same declarations get re-parsed over and over across a large codebase.

Modules are compiled once into an efficient binary interface file that's then loaded directly, without re-parsing.

Example: Why Modules are Better than Headers

cpp
// shapes.cppm
export module shapes;

export class Circle {
public:
	double radius;
};

// Unlike a #include'd header, this isn't re-parsed textually by every
// importing file -- the compiler processes it once and reuses the result.

C++20 export and import syntax

You define a module with export module ModuleName; at the top of a source file, marking specific declarations with export to make them part of the module's public interface.

Any file that wants to use it writes import ModuleName; instead of an #include directive.

Example: C++20 export and import syntax

cpp
// greet.cppm
export module greet;

export void sayHello() {
	// prints a greeting
}

// main.cpp:
// import greet;
// int main() { sayHello(); }

Preventing Symbol Collisions

Unlike headers, anything declared inside a module but not explicitly marked export stays entirely private to that module -- it can't leak into or collide with names in files that import it, which eliminates a whole category of naming conflicts common in large header-based projects.

Example: Preventing Symbol Collisions

cpp
// mathutils.cppm
export module mathutils;

int internalHelper(int x) { // not exported: stays private to this module
	return x * 2;
}

export int doubleValue(int x) {
	return internalHelper(x);
}

Modular Best Practices

Well-designed modules keep their exported interface small and deliberate -- only genuinely public functions and types should be exported, while internal helper functions and implementation details stay unexported, mirroring the public/private discipline you'd apply inside a class.

Example: Modular Best Practices

cpp
// account.cppm
export module account;

double calculateFee(double amount) { // internal detail, not exported
	return amount * 0.02;
}

export double totalWithFee(double amount) { // small, deliberate public interface
	return amount + calculateFee(amount);
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Using import without a compiler flag for C++20 modules such as -std=c++20, so the compiler does not understand it.
  2. Mixing #include and import of the same content and getting redefinition errors.
  3. Forgetting the export keyword, so the names in the module cannot be used by importing code.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.