Lessons
Inheritance and virtual functions
Base and derived classes, virtual and override, pure virtual (abstract classes), virtual destructors, and object slicing.
What to look for:
- Always declare destructors virtual in base classes — otherwise deleting via base pointer is UB
- override keyword: tells compiler "I intend to override" — catches typos in function signatures
- Pure virtual (= 0): makes the class abstract — cannot be instantiated directly
- Object slicing: assigning a Derived to a Base variable loses the derived part — use references or pointers
Function and class templates
template<typename T>, type deduction, class templates, template specialisation, and when templates beat virtual dispatch.
Prerequisite: Foundations Track
What to look for:
- Templates are reified — compiler generates a separate class per type (unlike Java erasure)
- Template definitions must be in headers — linker can't find them in .cpp files
- Template error messages are famously cryptic in C++17-; C++20 concepts improve this enormously
- Templates beat virtual dispatch when the type is known at compile time (zero-cost abstraction)
STL containers: vector, map, and unordered_map
std::vector (push_back, reserve, emplace_back), std::map (tree, sorted, O(log n)), std::unordered_map (hash, O(1) avg), and choosing between them.
Prerequisite: Lesson 2
What to look for:
- vector is the default container — prefer it unless you have a specific reason not to
- reserve() prevents repeated reallocations: v.reserve(1000) before inserting 1000 elements
- map iteration order is sorted by key; unordered_map iteration order is undefined
- unordered_map requires a hash function — custom types need you to provide one
STL algorithms and lambdas
std::sort, find_if, count_if, transform, accumulate; lambda syntax ([capture](params){body}); capture modes [=], [&], [this].
Prerequisite: Lesson 3
What to look for:
- Lambdas are anonymous function objects — they can capture local variables
- [&] capture by reference is efficient but dangerous if the lambda outlives the captured variable
- std::sort is O(n log n) guaranteed (introsort: quicksort + heapsort hybrid)
- accumulate with a custom binary op can do any fold: product, concatenation, max
Modern syntax: auto, range-for, and structured bindings
auto type deduction, range-for loops, structured bindings (C++17), if constexpr, and std::optional.
Prerequisite: Lessons 1–4
What to look for:
- auto deduces the type at compile time — it is not dynamic typing
- const auto& in range-for: avoids copying expensive objects during iteration
- Structured bindings: auto [key, value] = pair — unpacks pair, tuple, or struct fields
- std::optional: a value that may or may not be present — replaces -1 sentinel and output parameters
How to use this track: Each lesson links to the deep-dive reference pages. Compiler Explorer at godbolt.org lets you see what assembly each pattern generates — a great way to understand zero-overhead abstractions.
Track quiz
4 questions to check your understanding.
Why must base class destructors be declared virtual?
Where must C++ template definitions be placed?
What does auto [key, value] = pair do (C++17)?
What is the average time complexity of std::unordered_map lookup?