armhub.dev
Programming · 55 pages
Programmingtutorial

C++ programming tutorial — from C-with-classes to modern C++23

A 15-lesson hands-on tutorial taking you through classes, RAII, templates, the STL, smart pointers, move semantics, lambdas, modules, and modern C++23. Built for C programmers and embedded engineers.

3 min read · 671 wordsupdated · May 13, 2026

C++ is the most misunderstood language in the embedded world. People who learned it from a 2003 textbook remember iostream, multiple inheritance, RTTI, exceptions, and a fat runtime — and they refuse to touch it. People who learned it from a 2019 talk remember constexpr, ranges, concepts, and zero-overhead abstractions — and they cannot imagine why anyone would still write C. The truth lives between the two, and the difference comes down to which subset of the language you actually use.

This tutorial teaches the modern subset. The features that earn their keep: classes and RAII, templates, the STL containers you will actually reach for, smart pointers, move semantics, lambdas, ranges, and the C++23 additions like std::expected. It skips the historical baggage you can safely ignore: iostream formatting machinery, RTTI, exceptions on small targets, multiple inheritance soup, and the SFINAE tricks that concepts replaced.

By the end you will be able to read modern C++ codebases, write small libraries, use the STL without surprises, and — in the final lesson — apply what you learned to a Cortex-M target with arm-none-eabi-g++, knowing exactly which features cost what.

At a glance

C++ tutorial — at a glance
Target
Portable C++23 (or C++20 with explicit fallbacks for ranges, concepts, modules)
Hardware required
None — runs on any host (Linux, macOS, Windows). Lesson 15 connects to Cortex-M.
Software
Any C++23-aware compiler: gcc 13+, clang 17+. We use g++ -std=c++23 -Wall -Wextra -Wpedantic.
Time investment
Approximately 25-35 hours total — 90-120 minutes per lesson
Prerequisites
Basic C (pointers, structs, headers) or fluency in another statically typed language. No prior C++ required.
You will write
About 3000 lines of C++ across 15 short, self-contained programs
Output
Working programs covering classes, RAII, templates, STL, smart pointers, move semantics, lambdas, ranges, modules, and an embedded-flavoured capstone

Philosophy

Three rules govern every lesson.

Use the features that pay for themselves at compile time. Templates, constexpr, concepts, and the type system are free at runtime — they cost compile time and they buy you safety. Use them liberally.

Be skeptical of features that pay at runtime. Virtual functions, std::function, std::shared_ptr, exceptions, and dynamic allocation all have costs that show up in your final binary and your worst-case execution time. Use them when you need polymorphism, ownership counting, or error propagation that the alternatives cannot give you — not because the textbook said you should.

Embedded relevance is a callout, not a detour. Every lesson has a "Embedded callout" section that says what changes when you target a Cortex-M with no heap, no exceptions, and a 100 KB flash budget. Most C++ features survive that constraint with minor tweaks. A few do not. You will know which by lesson 8.

How this differs from the reference page

/docs/programming/cpp/ is the reference: a flat list of C++ features with embedded-flavoured advice on each, suitable for someone who already knows C++ and wants to know what to use on Cortex-M. It does not teach the language; it filters it for firmware engineers.

This tutorial is the course: an ordered 15-lesson path from "I know C, what does C++ add?" to "I can write a templated, RAII-managed, move-aware library and ship it on bare metal." Read this first. After lesson 15, the reference page becomes a quick lookup for any feature you forgot. The two are paired: tutorial for learning, reference for living.

The 15 lessons

Cortex-M lineup
sort:
CoreArchPipeDMIPSFPUDSPMPUTZMVENotes
Cortex-M0ARMv6-M3-stage0.84/MHz—Subset of Thumb-2.
Cortex-M0+ARMv6-M2-stage0.95/MHz—Single-cycle I/O port.
Cortex-M23ARMv8-M Baseline2-stage0.99/MHz—Secure & non-secure worlds.
Cortex-M3ARMv7-M3-stage1.25/MHz—The classic mid-range core.
Cortex-M33ARMv8-M Mainline3-stage1.50/MHzSPUsed in nRF53, STM32L5/U5.
Cortex-M4ARMv7E-M3-stage1.25/MHzSPMost popular general-purpose MCU core.
Cortex-M55ARMv8.1-M4-stage1.6/MHzSP/DP4–5× DSP/ML uplift vs. M4.
Cortex-M7ARMv7E-M6-stage2.14/MHzSP/DPUsed in i.MX RT, STM32H7.
Cortex-M85ARMv8.1-M7-stage3.0/MHzSP/DPi.MX RT700, Renesas RA8.

This page covers part 1: the landing page and lessons 1 through 8. Lessons 9 through 15 live in parts 2 and 3 of the tutorial.

How to use this tutorial

Four rules.

  1. Read in order. Each lesson assumes the last. Lesson 4 (inheritance) makes no sense without lesson 3 (classes). Lesson 7 (algorithms) assumes the containers from lesson 6. The dependencies are real and they are dense.

  2. Type the code. Every code block in this tutorial is real, compileable, and short. Type it into a file, compile with g++ -std=c++23 -Wall -Wextra -Wpedantic, and run it. Reading C++ from a webpage and never compiling is the most common way to fool yourself into thinking you have learned C++.

  3. Do the exercises before reading the answers. Two or three exercises end each lesson. Answers are in <Callout type="spec"> blocks below them. Skipping the exercises and reading the answers feels efficient and is the slowest way to learn.

  4. Use the warnings. -Wall -Wextra -Wpedantic catches real bugs. When the compiler complains, read the message. C++ compiler errors look ugly but they are usually right. The first 20 you decode by hand will earn you a sense for the next 200.

What you will not learn here

This tutorial deliberately omits:

  • Multiple inheritance and virtual inheritance beyond a one-paragraph mention. They exist; they are rarely the right answer; the patterns that justify them (mixins, interface inheritance with default implementations) are better served by composition plus templates.
  • The full template metaprogramming toolkit. SFINAE, std::enable_if, tag dispatch — concepts (C++20) replaced 90% of this. We mention the old names so you can read existing code, and move on.
  • C++ exceptions as the primary error model. We cover them in lesson 11 alongside the alternatives (std::optional, std::expected). For embedded targets, exceptions are usually off.
  • Boost and other large external libraries. We stick to the standard library so the lessons compile anywhere g++ runs.

If you need any of these later, the C++ Programming Language reference (Stroustrup) and cppreference.com are exhaustive. This tutorial gets you to the point where those references are useful.

Compiler setup, in 30 seconds

On macOS:

brew install gcc
g++-14 --version

On Linux:

sudo apt install g++-13     # Ubuntu 24.04 has g++-13; 24.10 has g++-14
g++ --version

On Windows: install MSYS2 and pacman -S mingw-w64-ucrt-x86_64-gcc, or use WSL.

Every example in this tutorial compiles with:

g++ -std=c++23 -Wall -Wextra -Wpedantic -O2 file.cpp -o file

If your compiler does not support -std=c++23, fall back to -std=c++20. Lessons 13 and 14 will then need adjustments noted inline. clang++ works identically — replace g++ with clang++ in every command.

Cross-references

  • C tutorial — the 10-lesson bare-metal C tutorial. If you do not yet know C confidently, start there.
  • C++ on Cortex-M — the reference page. Use it after this tutorial as a lookup for embedded-specific advice.
  • Bare-metal C tutorial — register-level C on STM32. Lesson 15 of this tutorial connects back to it.
  • GCC flags reference — every flag in our build commands explained.

Start with Lesson 1 — Hello, C++.