Lecture 1 / 12
Lecture 01 · Foundations

What is C++?

Beginner ~35 min No prerequisites

Introduction

C++ is a compiled, general‑purpose programming language created by Bjarne Stroustrup in 1985 as an extension of the C language. It adds object‑orientation, generic programming, low‑level memory control and a massive standard library.

Key Characteristics

✅ Quick fact
The current standard is C++20, with C++23 on the horizon.

Hello World – Your First C++ Program

Save the following as hello.cpp, compile it, and run it.

hello.cpp
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

Compile and run (Linux/macOS/macOS, Windows‑WSL, or MinGW):

g++ -std=c++20 hello.cpp -o hello
./hello          # prints “Hello, World!”
🎯 Exercise 1.1

Install a C++ compiler (GCC, Clang or MSVC), write the program above, compile it and verify the output.

Lecture 02 · Foundations

Setting up the Compiler

Beginner ~40 min Requires: Lecture 01

Choosing a Toolchain

For learning you can pick any of these:

Verifying Installation

g++ --version
clang++ --version
cl
ℹ️ IDE Recommendation

VS Code with the C/C++ extension or JetBrains CLion give you IntelliSense, debugging, and project management out of the box.

Compiling with Flags

Common useful flags:

🎯 Exercise 2.1

Create a simple project with two source files (main.cpp and utils.cpp), compile them together, and run the resulting executable.

Lecture 03 · Foundations

Variables & Data Types

Beginner ~45 min Requires: Lecture 02

Fundamental Types

Type Size (typical) Example
bool 1 byte bool ok = true;
char 1 byte char c = 'A';
int 4 bytes int i = 42;
long / long long 8 bytes long long big = 123456789LL;
float 4 bytes float f = 3.14f;
double 8 bytes double d = 2.71828;

Signed vs Unsigned

Appending u makes an integer type unsigned (unsigned int or uint32_t). Unsigned types cannot represent negative values, which can be useful for bit‑wise operations.

Type Modifiers

Keywords that affect size and sign:

Variable Declaration & Initialisation

variables.cpp
int count = 0;                // initialise to zero
double price = 19.99;
char grade = 'A';
bool isReady = true;

unsigned int mask = 0xFF;
long bigNum = 123456789L;
🎯 Exercise 3.1

Write a program that declares one variable of each primitive type, prints their size using sizeof, and then swaps the values of two integer variables without using a temporary variable.

Lecture 04 · Foundations

Control Flow

Beginner ~45 min Requires: Lecture 03

If / else

IfDemo.cpp
int score = 85;

if (score >= 90) {
    std::cout << "Grade A" << std::endl;
} else if (score >= 80) {
    std::cout << "Grade B" << std::endl;
} else {
    std::cout << "Needs improvement" << std::endl;
}

Switch (C++17 foldable switch)

SwitchDemo.cpp
char choice = 'b';

switch (choice) {
    case 'a':
    case 'b':
    case 'c':
        std::cout << "Option a–c selected" << std::endl;
        break;
    default:
        std::cout << "Other option" << std::endl;
}

Loops

LoopDemo.cpp
int sum = 0;

for (int i = 1; i <= 5; ++i) {
    sum += i;
}
std::cout << "Sum = " << sum << std::endl;
🎯 Exercise 4.1

Write a program that prints the first 20 Fibonacci numbers using a while loop.

Lecture 05 · Foundations

Functions

Beginner ~40 min Requires: Lecture 04

Function Syntax

General form: return_type name(parameter_list) { body }

MathUtils.cpp
int add(int a, int b) {
    return a + b;
}

double average(const std::vector<int>& values) {
    int sum = 0;
    for (int v : values) sum += v;
    return static_cast<double>(sum) / values.size();
}

Function Overloading

Same name, different parameter types/counts.

OverloadDemo.cpp
int max(int a, int b) { return (a > b) ? a : b; }
double max(double a, double b) { return (a > b) ? a : b; }

Default Arguments

Supply a value that is used when the caller omits that argument.

void greet(const std::string& name = "World") {
    std::cout << "Hello, " << name << "!\n";
}
🎯 Exercise 5.1

Implement a factorial function (recursive) for int and an overloaded version that works with unsigned long long. Write a short driver that calls both.

Lecture 06 · Core Concepts

Object‑Oriented Programming

Intermediate ~55 min Requires: Lecture 05

Class Declaration

Person.hpp
class Person {
private:
    std::string name;
    int age;

public:
    Person(const std::string& name, int age)
        : name(name), age(age) {}

    const std::string& getName() const { return name; }
    int getAge() const { return age; }

    void birthday() { ++age; }
};

Inheritance

Employee.hpp
class Employee : public Person {
private:
    std::string department;

public:
    Employee(const std::string& name,
             int age,
             const std::string& dept)
        : Person(name, age), department(dept) {}

    const std::string& getDept() const { return department; }
};

Polymorphism (virtual functions)

ShapeDemo.cpp
class Shape {
public:
    virtual double area() const = 0;
    virtual ~Shape() {}
};

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return 3.14159 * radius * radius;
    }
};

int main() {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Circle>(2.5));

    for (const auto& s : shapes) {
        std::cout << "Area = " << s->area() << std::endl;
    }
}
🎯 Exercise 6.1

Model a simple library system: a base class Item with id and title, then derive Book and Magazine. Override a virtual printInfo() method for each derived class.

Lecture 07 · Core Concepts

Standard Library Containers

Intermediate ~50 min Requires: Lecture 06

Why use containers?

They provide generic, memory‑safe collections with well‑defined complexity guarantees.

Sequence containers

Associative containers

Basic usage examples

VectorDemo.cpp
#include <vector>
#include <iostream>

int main() {
    std::vector<int> numbers = { 1, 2, 3 };
    numbers.push_back(4);

    for (int n : numbers) {
        std::cout << n << ' ';
    }
    std::cout << std::endl;
}
MapDemo.cpp
#include <map>
#include <string>
#include <iostream>

int main() {
    std::map<std::string, int> scores;
    scores["Alice"] = 95;
    scores["Bob"]   = 87;

    for (const auto& kv : scores) {
        std::cout << kv.first << ": " << kv.second << std::endl;
    }
}
🎯 Exercise 7.1

Create a program that reads a list of words from the console, stores them in a std::unordered_set, and then reports how many unique words were entered.

Lecture 08 · Core Concepts

Templates & Generics

Intermediate ~55 min Requires: Lecture 07

Function templates

SwapTemplate.cpp
template<typename T>
void swapValues(T& a, T& b) {
    T tmp = a;
    a = b;
    b = tmp;
}

int main() {
    int x = 5, y = 10;
    swapValues(x, y);                // works for ints
    std::string s1 = "foo", s2 = "bar";
    swapValues(s1, s2);               // works for std::string
}

Class templates

SimpleVector.hpp
template<typename T, size_t N>
class SimpleVector {
    T data[N];

public:
    constexpr size_t size() const { return N; }

    T& operator[](size_t i) { return data[i]; }
    const T& operator[](size_t i) const { return data[i]; }
};

Template specialization

Provide a custom implementation for a particular type.

template<>
struct std::hash<MyType> {
    size_t operator()(const MyType& obj) const noexcept { … }
};
🎯 Exercise 8.1

Write a generic Stack<T> class with push, pop and top operations. Then specialise it for bool so that it stores bits compactly (you can use std::vector<bool> for simplicity).

Lecture 09 · Advanced

Modern C++ (C++11 +)

Intermediate ~60 min Requires: Lecture 08

Auto type deduction

auto x = 42;                // int
auto y = 3.14;               // double
auto z = std::vector<int>{1,2,3}; // deduced type

Range‑based for loop

std::vector<int> v = {1,2,3};
for (auto& n : v) {
    n *= 2;
}

Smart pointers

SmartPtrDemo.cpp
#include <memory>
#include <iostream>

struct Node {
    int value;
    std::unique_ptr<Node> next;

    Node(int v) : value(v) {}
};

int main() {
    auto head = std::make_unique<Node>(1);
    head->next = std::make_unique<Node>(2);
    std::cout << head->value << ", " << head->next->value << std::endl;
}

Lambda expressions

auto add = [](int a, int b) { return a + b; };
std::cout << add(3,4) << '\n';

constexpr

Compile‑time constants and functions.

constexpr int square(int x) { return x*x; }
static_assert(square(5) == 25);
🎯 Exercise 9.1

Write a program that uses a std::vector<int> of random numbers, then sorts them with std::sort using a lambda comparator that orders them in descending order.

Lecture 10 · Advanced

Exception Handling

Intermediate ~45 min Requires: Lecture 09

try / catch / finally

C++ has try, catch and throw. The finally pattern is emulated with RAII.

ExceptionDemo.cpp
#include <stdexcept>
#include <iostream>

double divide(double a, double b) {
    if (b == 0.0) throw std::runtime_error("Division by zero");
    return a / b;
}

int main() {
    try {
        std::cout << divide(10, 2) << std::endl;
        std::cout << divide(5, 0) << std::endl;
    } catch (const std::runtime_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

Custom exception types

class InvalidAgeException : public std::runtime_error {
public:
    InvalidAgeException(const std::string& msg) : std::runtime_error(msg) {}
};
🎯 Exercise 10.1

Implement a BankAccount class with deposit, withdraw and balance. Throw a custom InsufficientFundsException when a withdrawal would result in a negative balance and handle it in main.

Lecture 11 · Advanced

Concurrency

Intermediate ~60 min Requires: Lecture 10

Thread basics

C++11 introduced std::thread, std::mutex and related primitives.

ThreadDemo.cpp
#include <thread>
#include <iostream>

void worker(int id) {
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread " << id << ": " << i << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    t1.join();
    t2.join();
}

Mutex & lock_guard

std::mutex m;
{
    std::lock_guard<std::mutex> lock(m);
    // critical section
}

Thread pool (high‑level)

Standard C++ does not ship a thread pool, but you can build one with std::async or use a third‑party library.

AsyncDemo.cpp
#include <future>
#include <iostream>

int fib(int n) {
    if (n <= 1) return n;
    return fib(n-1) + fib(n-2);
}

int main() {
    auto fut = std::async(std::launch::async, fib, 30);
    std::cout << "Computing…" << std::endl;
    int result = fut.get();               // blocks until fib finishes
    std::cout << "Result = " << result << std::endl;
}
🎯 Exercise 11.1

Write a producer‑consumer example using a std::queue protected by a std::mutex and a std::condition_variable. One thread should push numbers 1‑100 into the queue, the other should pop and print them.

Lecture 12 · Capstone

Capstone Project – Console To‑Do List

Advanced ~90 min Requires: All Lectures

Implement a **single‑file** C++ console program that lets the user manage a simple To‑Do list.

Feature checklist

Starter skeleton

TodoApp.cpp
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>

struct Task {
    int id;
    std::string text;
    bool done;

    Task(int i, std::string t)
        : id(i), text(std::move(t)), done(false) {}

    std::string serialize() const {
        return std::to_string(id) + "," + text + "," + (done ? "1" : "0");
    }

    static Task deserialize(const std::string& line) {
        std::istringstream ss(line);
        std::string part;
        int i;
        std::getline(ss, part, ',');
        i = std::stoi(part);
        std::getline(ss, part, ',');
        std::string txt = part;
        std::getline(ss, part, ',');
        bool d = (part == "1");
        Task t(i, txt);
        t.done = d;
        return t;
    }
};

class TodoApp {
    static constexpr const char* FILE_NAME = "tasks.txt";
    std::vector<Task> tasks;
    int nextId = 1;

    void load() {
        std::ifstream in(FILE_NAME);
        if (!in) return;
        std::string line;
        while (std::getline(in, line)) {
            Task t = Task::deserialize(line);
            tasks.push_back(t);
            if (t.id >= nextId) nextId = t.id + 1;
        }
    }

    void save() {
        std::ofstream out(FILE_NAME, std::ios::trunc);
        for (const auto& t : tasks) {
            out << t.serialize() << \n;
        }
    }

    void printMenu() {
        std::cout << "\n--- To‑Do List ---\n";
        for (const auto& t : tasks) {
            std::cout << t.id << ". ["
                      << (t.done ? "x" : " ") << "] " << t.text << \n;
        }
        std::cout << "\n(a)dd, (t)oggle, (d)elete, (q)uit: ";
    }

    void addTask(const std::string& txt) {
        tasks.push_back(Task(nextId++, txt));
    }

    void toggleTask(int id) {
        for (auto& t : tasks) {
            if (t.id == id) { t.done = !t.done; break; }
        }
    }

    void deleteTask(int id) {
        tasks.erase(std::remove_if(tasks.begin(), tasks.end(),
                           [id](const Task& t){ return t.id == id; }),
                     tasks.end());
    }

public:
    TodoApp() { load(); }

    ~TodoApp() { save(); }

    void run() {
        while (true) {
            printMenu();
            std::string cmd;
            std::getline(std::cin, cmd);
            if (cmd.empty()) continue;
            char c = std::tolower(cmd[0]);
            if (c == 'q') break;

            switch (c) {
                case 'a':
                    std::cout << "Task description: ";
                    std::getline(std::cin, cmd);
                    addTask(cmd);
                    break;
                case 't':
                    std::cout << "ID to toggle: ";
                    std::getline(std::cin, cmd);
                    toggleTask(std::stoi(cmd));
                    break;
                case 'd':
                    std::cout << "ID to delete: ";
                    std::getline(std::cin, cmd);
                    deleteTask(std::stoi(cmd));
                    break;
                default:
                    std::cout << "Unknown command\n";
            }
        }
    }
};

int main() {
    TodoApp app;
    app.run();
    return 0;
}

What you’ll learn

🚀 Next steps

After this capstone you’ll be ready to move on to:

  • GUI programming (Qt, wxWidgets, SFML).
  • Modern C++ libraries (Boost, fmt, ranges).
  • Build systems (CMake, Meson).
  • Testing frameworks (GoogleTest, Catch2).
🎯 Final Challenge

Extend the app with a priority field (enum LOW/MEDIUM/HIGH) and allow sorting by priority. Add colour output (ANSI escape codes) so completed tasks appear in grey.