---
title: 'C++ Fundamentals and Object Design'
source: 'https://academia.sh/en/courses/cpp-fundamentals'
language: en
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
lessons: 14
outcomes:
    - 'Sets up the class, constructor and destructor life cycle correctly'
    - 'Automates resource management with RAII'
    - 'Builds runtime polymorphism with inheritance and virtual functions'
    - 'Tells whether an expression works with the object itself, a copy, a part or a temporary, and measures it'
    - 'Recognizes where pass-by-value, slicing and implicit conversion construct a new object'
---

# C++ Fundamentals and Object Design

In C++, two expressions that look the same can work with different objects: the course measures every mechanism with a single question — which object is this expression working with; the named object itself, a new object copied from it, a part inside it, or a temporary that vanishes at the end of the line? Classes, constructors and destructors, RAII, copying, references, inheritance, virtual functions, exceptions and type conversions all pass through the same frame.

## Classes and Resources

Where C and C++ diverge, access control, constructors and destructors, RAII, deep and shallow copies, references and operator overloading — each paired with the question of which object an expression works with.

### C and C++ Differences

Source: https://academia.sh/en/courses/cpp-fundamentals/c-and-cpp-differences

Introduces the course's four measurement kinds with a core run that measures which object a struct passed by value in C works with in C++.

In M11/K03, "Object-Like Design" imitated object behavior in C by hand-assembling a
struct together with function pointers bound to it; which function ran was stored in a
manually built table. This course asks the same question with C++'s own language
features: **which object, exactly, does an expression work with** — the named object
itself, a new object copied from it, a part inside it, or an unnamed, short-lived
object?

#### The Measurement Axis

Throughout the course, every lesson places an expression into one of four kinds:

- **self** — the expression works with the whole of the named object.
- **copy** — the expression works with a new object constructed by copying from the
  named object.
- **part** — the expression works with a subobject inside the named object.
- **temporary** — the expression works with a new, unnamed object that dies at the end
  of the full expression.

These four kinds are not a guess but the result of a run: the core below traces every
expression through its address, its copy constructor's source, and its object's
lifetime, and determines the kind itself.

#### The Core's Full Run

The core is three files. `trace.hpp` and `trace.cpp` carry the tracing infrastructure:
every object gets a serial number on construction, and if it is copied it keeps its
source's number; `touch` records the object the expression actually works on, and
`finish` compares the declared kind against the measured one and prints the row.
`which_one.cpp` runs all fourteen measurements belonging to this course's fourteen
lessons inside a single `main`.

```cpp
// trace.hpp — a trace that measures which object an expression works on
#ifndef TRACE_HPP
#define TRACE_HPP

#include <cstddef>
#include <typeinfo>

enum class Kind { self, copy, part, temporary };

// Every traced object derives from this base: it gets a serial number when
// constructed, and if copied it keeps its source's number.
class Trace {
public:
    Trace();
    Trace(const Trace& source);
    Trace& operator=(const Trace& source);
    ~Trace();
    int id() const { return id_; }
    int source() const { return source_; }

private:
    int id_;
    int source_;
};

void begin_record(const void* addr, std::size_t size, const std::type_info& type, int id);
void touch_record(const void* addr, std::size_t size, const std::type_info& type,
                  const Trace* trace, int source);

// Records the named object: the measurement is made against this object.
template <class T>
void begin(const T& whole) {
    begin_record(&whole, sizeof whole, typeid(T), whole.id());
}

// Records the object the expression really works on and classifies it.
template <class T>
void touch(const T& obj) {
    touch_record(&obj, sizeof obj, typeid(T), &static_cast<const Trace&>(obj),
                 obj.source());
}

// Closes the measurement, compares the declared kind with the measured one, prints the row.
void finish(const char* expr, Kind declared);

// Prints the count per kind and the existing / new object totals.
void summary();

#endif
```

```cpp
// trace.cpp — the counts and the measurement state live only in this unit
#include "trace.hpp"

#include <cstdio>
#include <functional>

namespace {

int created = 0;
const char* const names[] = { "self", "copy", "part", "temporary" };
int counts[4] = {};
int existing = 0;
int fresh = 0;

const char* whole_addr = nullptr;
std::size_t whole_size = 0;
const std::type_info* whole_type = nullptr;
int whole_id = 0;

bool touched = false;
bool same = false;
bool inside = false;
bool copy_of = false;
bool ended = false;
const Trace* watched = nullptr;

}  // namespace

Trace::Trace() : id_(++created), source_(0) {}

Trace::Trace(const Trace& source) : id_(++created), source_(source.id_) {}

Trace& Trace::operator=(const Trace&) {
    return *this;  // assignment changes the object but constructs no new one
}

Trace::~Trace() {
    if (this == watched) {
        ended = true;
        watched = nullptr;
    }
}

void begin_record(const void* addr, std::size_t size, const std::type_info& type, int id) {
    whole_addr = static_cast<const char*>(addr);
    whole_size = size;
    whole_type = &type;
    whole_id = id;
    touched = same = inside = copy_of = ended = false;
    watched = nullptr;
}

void touch_record(const void* addr, std::size_t size, const std::type_info& type,
                  const Trace* trace, int source) {
    const char* start = static_cast<const char*>(addr);
    std::less<const char*> before;
    touched = true;
    same = start == whole_addr && size == whole_size && type == *whole_type;
    inside = !before(start, whole_addr) && !before(whole_addr + whole_size, start + size);
    copy_of = source == whole_id;
    ended = false;
    watched = trace;
}

void finish(const char* expr, Kind declared) {
    int measured = -1;
    if (touched) {
        if (same) {
            measured = static_cast<int>(Kind::self);
        } else if (inside) {
            measured = static_cast<int>(Kind::part);
        } else if (copy_of) {
            measured = static_cast<int>(Kind::copy);
        } else if (ended) {
            measured = static_cast<int>(Kind::temporary);
        }
    }
    int k = static_cast<int>(declared);
    bool exists = declared == Kind::self || declared == Kind::part;
    counts[k]++;
    if (exists) {
        existing++;
    } else {
        fresh++;
    }
    std::printf("%-36s %-8s %s%s\n", expr, exists ? "existing" : "new", names[k],
                measured == k ? "" : "  MISMATCH");
    watched = nullptr;
}

void summary() {
    std::printf("kinds: self %d, copy %d, part %d, temporary %d\n",
                counts[0], counts[1], counts[2], counts[3]);
    std::printf("existing %d, new %d\n", existing, fresh);
}
```

```cpp
// which_one.cpp — fourteen expressions, one question for each: which object
#include <algorithm>

#include "trace.hpp"

/* 1. C and C++ differences: struct passed by value */
struct Point : Trace {
    int x = 0;
    int y = 0;
};
static void shift(Point p) {
    p.x += 1;
    touch(p);
}
static void c_differences() {
    Point n;
    begin(n);
    shift(n);
    finish("struct passed by value", Kind::copy);
}

/* 2. Access control: the object a member function works on */
class Account : public Trace {
public:
    void deposit(int amount) {
        balance_ += amount;
        touch(*this);
    }
    int balance() const { return balance_; }

private:
    int balance_ = 0;
};
static void access() {
    Account a;
    begin(a);
    a.deposit(50);
    finish("this of a member function", Kind::self);
}

/* 3. Constructors: the object a converting constructor builds */
class Quantity : public Trace {
public:
    Quantity(int value) : value_(value) {}  // not explicit: converts from int
    int value() const { return value_; }

private:
    int value_;
};
static int show(const Quantity& q) {
    touch(q);
    return q.value();
}
static void constructors() {
    Quantity q(3);
    begin(q);
    show(5);
    finish("argument built from an int", Kind::temporary);
}

/* 4. RAII: the member the guard releases */
class Resource : public Trace {
public:
    void acquire() { held_ = true; }
    void release() {
        held_ = false;
        touch(*this);
    }

private:
    bool held_ = false;
};
class Guard {
public:
    explicit Guard(Resource& r) : r_(r) { r_.acquire(); }
    ~Guard() { r_.release(); }
    Guard(const Guard&) = delete;
    Guard& operator=(const Guard&) = delete;

private:
    Resource& r_;
};
class Counter : public Trace {
public:
    void increment() {
        Guard g(resource_);
        value_++;
    }

private:
    Resource resource_;
    int value_ = 0;
};
static void raii() {
    Counter c;
    begin(c);
    c.increment();
    finish("member released by the guard", Kind::part);
}

/* 5. Copying: a deeply copied buffer */
class Buffer : public Trace {
public:
    explicit Buffer(int size) : size_(size), data_(new int[size]()) {}
    Buffer(const Buffer& other) : Trace(other), size_(other.size_), data_(new int[other.size_]) {
        std::copy(other.data_, other.data_ + other.size_, data_);
    }
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            int* fresh = new int[other.size_];
            std::copy(other.data_, other.data_ + other.size_, fresh);
            delete[] data_;
            data_ = fresh;
            size_ = other.size_;
        }
        return *this;
    }
    ~Buffer() { delete[] data_; }
    void write(int i, int value) {
        data_[i] = value;
        touch(*this);
    }
    int read(int i) const { return data_[i]; }

private:
    int size_;
    int* data_;
};
static void copying() {
    Buffer a(3);
    begin(a);
    Buffer b(a);
    b.write(0, 9);
    finish("deeply copied buffer", Kind::copy);
}

/* 6. References: an object passed by reference */
static void nudge(Point& p) {
    p.y += 1;
    touch(p);
}
static void references() {
    Point n;
    begin(n);
    nudge(n);
    finish("struct passed by reference", Kind::self);
}

/* 7. Operator overloading: the result of a + b */
class Money : public Trace {
public:
    explicit Money(int cents) : cents_(cents) {}
    Money operator+(const Money& b) const { return Money(cents_ + b.cents_); }
    Money& operator+=(const Money& b) {
        cents_ += b.cents_;
        return *this;
    }
    int cents() const { return cents_; }

private:
    int cents_;
};
static int use_money(const Money& m) {
    touch(m);
    return m.cents();
}
static void operators() {
    Money a(150);
    Money b(250);
    begin(a);
    use_money(a + b);
    finish("result of a + b", Kind::temporary);
}

/* 8. Inheritance: a function of the base class */
class Vehicle : public Trace {
public:
    void accelerate() {
        speed_++;
        touch(*this);
    }

private:
    int speed_ = 0;
};
class Truck : public Vehicle {
public:
    int load() const { return load_; }

private:
    int load_ = 0;
};
static void inheritance() {
    Truck t;
    begin(t);
    t.accelerate();
    finish("function of the base class", Kind::part);
}

/* 9. Virtual functions: virtual call via base reference */
class Shape : public Trace {
public:
    virtual ~Shape() = default;
    virtual void draw() const { touch(*this); }
};
class Circle : public Shape {
public:
    void draw() const override { touch(*this); }

private:
    int radius_ = 1;
};
static void virtuals() {
    Circle c;
    begin(c);
    const Shape& s = c;
    s.draw();
    finish("virtual call via base reference", Kind::self);
}

/* 10. Abstract classes: a call through an interface */
class Logger : public Trace {
public:
    virtual ~Logger() = default;
    virtual void log() = 0;
};
class LineLogger final : public Logger {
public:
    void log() override {
        lines_++;
        touch(*this);
    }

private:
    int lines_ = 0;
};
static void use(Logger& l) {
    l.log();
}
static void abstraction() {
    LineLogger l;
    begin(l);
    use(l);
    finish("call through an interface", Kind::self);
}

/* 11. Multiple inheritance: the single subobject of a virtual base */
class Device : public Trace {
public:
    void power_on() {
        on_ = true;
        touch(*this);
    }

private:
    bool on_ = false;
};
class Printer : public virtual Device {
    int pages_ = 0;
};
class Scanner : public virtual Device {
    int resolution_ = 0;
};
class MultiFunction : public Printer, public Scanner {};
static void diamond() {
    MultiFunction m;
    begin(m);
    m.power_on();
    finish("subobject of the virtual base", Kind::part);
}

/* 12. Exceptions: an exception caught by value */
class Error : public Trace {
public:
    explicit Error(int code) : code_(code) {}
    int code() const { return code_; }

private:
    int code_;
};
static void exceptions() {
    const Error* thrown = nullptr;
    try {
        try {
            throw Error(7);
        } catch (const Error& inner) {
            thrown = &inner;
            throw;
        }
    } catch (Error e) {
        begin(*thrown);
        touch(e);
        finish("exception caught by value", Kind::copy);
    }
}

/* 13. Namespaces: an object named by a using declaration */
namespace accounting {
class Ledger : public Trace {
public:
    void post() {
        entries_++;
        touch(*this);
    }

private:
    int entries_ = 0;
};
Ledger main_ledger;
}  // namespace accounting

static void namespaces() {
    using accounting::main_ledger;
    begin(accounting::main_ledger);
    main_ledger.post();
    finish("object named by a using declaration", Kind::self);
}

/* 14. Type conversions: a reference converted to the base */
class Meter : public Trace {
public:
    void read() const { touch(*this); }
};
class Thermometer : public Meter {
public:
    int degrees() const { return degrees_; }

private:
    int degrees_ = 20;
};
static void conversions() {
    Thermometer t;
    begin(t);
    static_cast<const Meter&>(t).read();
    finish("reference converted to the base", Kind::part);
}

int main() {
    c_differences();
    access();
    constructors();
    raii();
    copying();
    references();
    operators();
    inheritance();
    virtuals();
    abstraction();
    diamond();
    exceptions();
    namespaces();
    conversions();
    summary();
    return 0;
}
```

```text
struct passed by value               new      copy
this of a member function            existing self
argument built from an int           new      temporary
member released by the guard         existing part
deeply copied buffer                 new      copy
struct passed by reference           existing self
result of a + b                      new      temporary
function of the base class           existing part
virtual call via base reference      existing self
call through an interface            existing self
subobject of the virtual base        existing part
exception caught by value            new      copy
object named by a using declaration  existing self
reference converted to the base      existing part
kinds: self 5, copy 3, part 4, temporary 2
existing 9, new 5
```

**CR1.** Five of the fourteen expressions worked with self, three with a copy, four
with a part, two with a temporary; the course's four kinds and their distribution are
born from this. The first row is this lesson's subject: `shift(Point p)` works with
the `p` it receives by value, and `p` is constructed by copying from `n` — the
`p.x += 1` inside `shift(n)` does not reach the caller's `n`. Passing a `struct` by
value in C gives the same result; C++ did not change this behavior, it added a new
option on top of it.

#### Deepening the Struct Passed by Value

The reference parameter C++ adds to C carries the same call into a different kind.
The measurement below runs `shift` and `nudge` side by side in its own `main`; both
are called through `n`, both appear in the source with the `(n)` spelling, but one
takes it by value and the other by reference.

```cpp
// value-reference.cpp — same call syntax, different parameter declaration
#include <cstdio>

struct Point {
    int x = 0;
};

static void shift(Point p, const Point* outside) {
    p.x += 1;
    std::printf("shift: is p the same object as outside %s\n",
                &p == outside ? "yes" : "no");
}

static void nudge(Point& p, const Point* outside) {
    p.x += 1;
    std::printf("nudge: is p the same object as outside %s\n",
                &p == outside ? "yes" : "no");
}

int main() {
    Point n;
    shift(n, &n);
    nudge(n, &n);
    return 0;
}
```

```text
shift: is p the same object as outside no
nudge: is p the same object as outside yes
```

**CR2.** The `p` inside `shift(n)` is a separate object from the caller's `n` — of
kind copy. The `p` inside `nudge(n)` is the caller's `n` itself — of kind self. The
call syntax is `(n)` in both cases; the only thing that makes the difference is the
function's **declaration**: whether the parameter type is `Point` or `Point&`.

#### C++'s Differences from C

This lesson measured only pass-by-value; the rest of the elements C++ adds to C are
measured one by one in the course's later lessons. Briefly counted: `class` and
access control, the reference type, operator overloading, `new`/`delete`, namespaces,
a distinct `bool` type, and stricter type checking than C — for example, the implicit
conversion from `void*` to another pointer type is permitted in C, but is a compile
error in C++.

#### The Bounding Measurement

The expression this lesson measures is of kind **copy**, but the measurement itself
also reveals a limit: the call site does not **say** which kind it will work with.
`shift(n)` and `nudge(n)` look identical in the source — both call an identifier in
parentheses with `n`. Only the parameter type in the function's declaration
determines which object is worked with; a reader must infer this decision from the
signature, not from the call line.

#### Summary

- The course's measurement axis: an expression works with one of the kinds **self**,
  **copy**, **part**, or **temporary**; the fourteen measurements fix this
  distribution as 5/3/4/2.
- The expression this lesson measures is of kind **copy**: the `Point` passed by
  value works with a copy separate from the caller's object.
- The same `(n)` call syntax shifts to kind **self** when the parameter is a
  reference; it is the declaration, not the call, that determines the kind.
- The elements C++ adds to C (class, reference, overloading, `new`/`delete`,
  namespace, `bool`, stricter type checking) were briefly counted; each deepens in
  its own lesson.
- Compilation is warning-free and the output is identical across three separate
  runs; the measurement rests on a run, not a guess.

#### Next Step

This lesson showed which object a function works with based on its parameter type;
the next lesson asks the same question for a **member function** — it measures which
object `this` points to when `a.deposit(50)` is called, and that `private` access
works at the level of the class, not the object.

### Classes and Access Control

Source: https://academia.sh/en/courses/cpp-fundamentals/classes-and-access-control

Measures which object a member function works with, and that access control operates at the level of the class, not the object.

The previous lesson measured which object a free function works with by looking at its
parameter: `shift(Point n)` worked with its own copy, `nudge(Point* p)` reached the
caller's object through an address. A member function also has a parameter, but the
compiler passes it implicitly: the address of the object the call was made on. This
implicit parameter's name is `this`, and it is available throughout a member function's
body — present even when not written. This lesson measures that same implicit parameter
with the same core instrument: when a member function is called, which object does
`this` point at, and how does that fact meet access control?

#### Classes and Access Control

`class` and `struct` are the same thing in C++; both define a type that can carry data
members and member functions, both can be inherited from, both run a constructor and a
destructor. The only difference between them is the default access level. A `struct`'s
members are `public` by default, a `class`'s members are `private` by default — no other
behavioral difference exists. This is an inheritance from C: in C, a `struct` was only a
data-carrying record, it carried no functions; when C++ gave `struct` the ability to
carry member functions, it kept the default access `public` for backward compatibility.
Using `struct` for types that mostly carry data with little behavior, and `class` for
types whose behavior is protected by access control, is a convention in a C++ codebase —
the language itself does not enforce it.

A class declares three access levels:

- `public` — reachable from outside the class, from any code, anywhere. A class's
  outward-facing **interface** lives here.
- `private` — reachable only from the class's own member functions (and from functions
  or classes declared as `friend`). The data members that hold a class's own internal
  state are usually here.
- `protected` — reachable from the class's own member functions and from derived
  classes; its difference from `private` only shows up under inheritance. Inheritance
  is not used in this course until M11/K04's second topic, so `protected` is only named
  here.

An access-level declaration (`public:`, `private:`, or `protected:`) applies, inside a
class body, to every member after that point, up to the next access-level declaration.
In the `Account` class, the three member functions under `public:` are callable from
outside; `balance_` under `private:` is not — the same class body can also contain more
than one `public:`/`private:` block, and the compiler merges them all.

A class carries **data members** (a variable with its own copy in every instance of the
object — `balance_` carries its own value in every `Account` object) and **member
functions** (code shared across all instances of the class, reaching the called
instance's data members through `this` — `deposit`'s machine code is generated once, not
separately for every `Account` object). If a member function is marked `const`, `this`
itself is `const`: the function cannot modify data members, only read them. `balance()`
and `equals` are `const` for this reason — both read `balance_` without modifying it;
`deposit` is not `const` because it modifies `balance_`. Only `const` member functions
can be called on a `const` object; calling a non-`const` member function on a `const`
object is a compile error, because the compiler cannot guarantee that `this` will not be
modified inside the function.

A `friend` declaration grants a function or class, which is not itself a member, access
to a class's `private` members — the sole exception to access control, and one granted
explicitly by the class's own declaration, never taken from outside. In this course,
`friend` is used exactly once, so that `operator<<` can read a class's `private` data
member (in the Operator Overloading lesson); here it is only named.

Encapsulation — hiding a class's internal state from the outside and exposing access
only through functions — was already covered in M08; it is not retaught here, only
applied through C++'s `public`/`private` syntax. `Account` applies this idea: `balance_`
cannot be written to directly from outside, it can only be changed through `deposit`.

#### A Member Function's this

`this` is an implicitly defined pointer inside a member function's body; its type is
determined by the class it was called on. Inside `Account::deposit`, `this`'s type is
`Account* const` — the pointer itself cannot be changed (it cannot start pointing at a
different `Account`), but the object it points at can be modified. Inside a `const`
member function — such as `Account::balance() const` — `this`'s type is `const Account*
const`: neither the pointer nor the object it points at can be modified, which is why a
`const` member function only gains read access to data members. Code does not write this
pointer by hand — `balance_ += amount` is read by the compiler as `this->balance_ +=
amount` — but the measurement below shows plainly that `this` really does point at the
called object, not some other object: the address `&h` captured before the call to
`h.deposit(50)` is compared against the equivalent of `this` used implicitly inside the
function.

```cpp
// account.hpp — an account whose balance is private
#ifndef ACCOUNT_HPP
#define ACCOUNT_HPP

class Account {
public:
    void deposit(int amount) { balance_ += amount; }
    int balance() const { return balance_; }
    bool equals(const Account& other) const { return balance_ == other.balance_; }

private:
    int balance_ = 0;
};

#endif
```

```cpp
// this-measurement.cpp — does the member function's this point at the called object
#include <cstdio>
#include "account.hpp"

int main() {
    Account a;
    Account* before = &a;

    a.deposit(50);
    std::printf("does this point at the called object %s\n", before == &a ? "yes" : "no");
    std::printf("balance %d\n", a.balance());
    return 0;
}
```

```text
does this point at the called object yes
balance 50
```

**CR3.** The compiler passes `&a` as `this` in the call `a.deposit(50)`; the line
`balance_ += amount` inside `deposit` modifies `a.balance_`, no other `Account`. This
expression is of kind **self**: it works with `a` itself.

#### Access Control Asks About the Class, Not the Object

`balance_` is `private`; it cannot be written from outside `Account` — a line like that
attempted inside `main` is rejected by the compiler, because `main` is not a member of
the `Account` class. But `Account`'s own member function can reach directly into
**another** `Account` object's `balance_` — access control asks about the class, not the
object. `equals` shows this: `other.balance_` is not the caller's own `balance_`, but it
compiles because it belongs to the same class. This is a C++ rule that does not hold in
many languages — in some languages access control works at the object level and an
object can only touch its own data; in C++ the boundary is the class itself, not a
single object.

```cpp
// equals-measurement.cpp — a member function reaching another object's private member
#include <cstdio>
#include "account.hpp"

int main() {
    Account a;
    Account b;
    a.deposit(30);
    b.deposit(30);

    std::printf("are a and b equal %s\n", a.equals(b) ? "yes" : "no");

    b.deposit(1);
    std::printf("are a and b equal %s\n", a.equals(b) ? "yes" : "no");
    return 0;
}
```

```text
are a and b equal yes
are a and b equal no
```

**CR4.** The access `other.balance_` inside `a.equals(b)` reaches `b`'s `private` member
from `a`'s member function; the compiler accepts this only by looking at `other`'s type
(`const Account&`), not at whether `a` and `b` happen to be the same object. The access
decision is made **at compile time**, from the class information.

This is one of the points where many C++ learners are first surprised: `private` is
assumed to mean "only this object can access its own data," but the actual rule is
"only this **class**'s member functions can access it." While `equals`'s body is
compiled, the compiler only knows this: `other` is a `const Account&`, and the function
currently being compiled is a member of the `Account` class; these two facts are enough
to permit the access `other.balance_`. Whether `a` and `other` (that is, `b`) are the
same runtime object is not known at compile time and plays no part in the access
decision at all — indeed, in the second call `a` and `b` are separate objects and the
access still compiles.

#### Why private Protects the Class, Not the Object

This rule is not arbitrary; it makes it possible for a class's author to protect its
**invariants** (a condition that must always hold for an object — for example, that
`balance_` must never drop below zero). If `private` only meant "reachable from your own
object, not from other objects," functions like `equals` that compare two objects, or
functions that copy data from one object into another, could not be written — every
member function could only look at its own `this`. Class-level access lets a class's own
member functions safely share data among themselves, while closing that same data off to
code outside the class. The boundary it draws is not the object — it is **the
declaration in the class's own source file.**

The opposite of this is a struct with an open field: in a record like that, calling code
can change that field without passing through any check at all. `Account` does not make
that mistake — there is no path to write `balance_` from outside, it can only be changed
through `deposit`. `deposit` today does nothing beyond `balance_ += amount`, but because
of `private`, a rule could later be added — rejecting a negative `amount`, or enforcing
an upper bound — and that rule could be written into `deposit` alone, without changing
any caller, because the **only** path to `balance_` is `deposit`. This is the real
engineering value `private` buys: the freedom to change the class's internal
representation without touching the code outside it.

#### Choosing Which Call a const Object Allows

The question of why `balance()` and `equals` are marked `const` while `deposit` is not
has a practical consequence: a function taking a `const Account&` parameter can only
call `const` member functions through that parameter. `equals`'s signature is `bool
equals(const Account& other) const`; its body accesses `other.balance_` directly, but it
would also compile if it called `other.balance()` instead — because `balance()` is
`const` and a `const` function can be called through a `const` reference. Had
`other.deposit(10)` been attempted, it would not compile: `deposit` is not `const`, and
a non-`const` member function cannot be called on a `const` object (or on the object a
`const` reference points at). This rule shows that writing `const` in a function's
signature is not merely a documentary note — it is a contract the compiler actually
enforces: that `equals` will not modify `other` is verified at compile time from the
function's own signature.

The same rule applies to `this`. Because `Hesap::equals` — `Account::equals` — is marked
`const`, its own `this` is also `const Account* const`; if a change such as
`balance_ += 1` were attempted inside this function's body — even on its own object —
the compiler rejects it. A `const` member function can modify neither its own object nor
another object it received by `const` reference; the only things it can modify are local
variables and data members marked `mutable` (`mutable` is a marker reserved for rare
cases such as caching, and it is not used in this course).

#### Declaration Order and Access-Level Blocks

In the `Account` class, the access-level declarations follow a particular layout order:
first the member functions exposed to the outside under `public:`, then the data member
under `private:`. This order is not a rule of the language — the compiler would produce
the same result if `private:` came first and `public:` came after — but it is a common
habit for readability: someone reading a class first sees the interface it offers, then
the internal representation. The reverse order (`private` data first, `public` functions
after) is equally valid and preferred in some codebases; this lesson follows the
`public`-first order and stays consistent with it for the rest of the course.

An access-level declaration is not required to be used only once — `public:` and
`private:` can each repeat more than once within the same class body, each covering the
block that follows it. `Account` does not do this; because the class is small, a single
`public:` and a single `private:` are enough. In a larger class, using more than one
block to keep related members together — a separate `public:` for constructors, a
separate `public:` for query functions, for example — can improve readability; this is a
style choice, it does not change the compiler's behavior.

#### The Bounding Measurement

The expression this lesson measures is of kind **self**: `h.deposit(50)` writes to `h`
itself. But the boundary of access control is visible here too: "who accesses" a
`private` member is asked at the level of the class, not the object. The call to
`other.balance_` inside `equals` proves this — a `private` member of a different object
of the same class can be reached, without that object's own function, from just another
member function of the same class. `private` protects the class's boundary, not the
object.

This boundary has a further consequence: access to a `private` member is possible from
every member function in the class's **own** source code — the number of such member
functions can grow as the class grows, and each one carries the same risk of breaking
the same invariant. `Account` is small, with three member functions, and all of them are
visible in this lesson; a large class can have dozens of member functions that reach
`private` data, and the rule measured in this lesson — that access is tied to the class,
not the object — remains unchanged at that scale too. `private` answers the question "how
many places can reach this" not with a count of objects, but with the class's count of
member functions.

These two points — which object a given expression works with, and that access control
asks about the class, not the object — together explain why a class can draw a reliable
boundary. `this` points at the correct object on every call, so a member function never
confuses its own object with another; `private` grants every member function access to
every object of the same class, so the class can write operations that require sharing
data internally (comparison, copying, merging). These two rules together lay the ground
for the next lesson's subject, the constructor: a constructor is also a member function,
it has its own `this`, and it reaches `private` data members with the same freedom — but
what sets it apart is that the object it is called on does not yet exist.

#### Summary

- The expression this lesson measures is of kind **self**: in the call `h.deposit(50)`,
  `this` equals `&h`.
- The only difference between `class` and `struct` is the default access level;
  `public`/`private`/`protected` declare three access levels.
- Inside a `const` member function, `this` is itself `const`; data members cannot be
  modified.
- Access control operates **at compile time** and **at the level of the class**: a
  member function can reach a `private` member of a different object of the same class.
- Encapsulation was defined in M08; here it was only applied through `class`/`private`
  syntax.

#### Next Step

This lesson showed which object a member function works with; the next lesson asks the
same question of a **constructor** — it measures that an argument implicitly built from
an `int` is an unnamed, temporary object, and exactly when that object ceases to exist.

### Constructors and Destructors

Source: https://academia.sh/en/courses/cpp-fundamentals/constructors-and-destructors

Measures that an argument implicitly built from an int is an unnamed, temporary object, and measures its lifetime with a constructor/destructor pair.

The previous lesson measured which object a member function works with, through `this`
— but that object always already existed. This lesson asks the same question at the
**moment an object comes to exist**: when is a **constructor** (a member function
carrying the same name as the class, run once while the object is being built) called,
and when does a **destructor** (a member function prefixed with `~`, run once while the
object is being destroyed) run? This time the measurement kind is **temporary**: it will
track the lifetime of an unnamed object, implicitly built from an argument of a function
call.

#### Constructor and Destructor

A constructor carries the same name as the class, has no return type (not even `void`
is written), and is called by the compiler while an object is being built. A destructor
takes the form `~ClassName()`, takes no arguments, and is called by the compiler when an
object reaches the end of its lifetime — the programmer never calls it by hand. If a
class writes no constructor at all, the compiler generates a **default constructor**
(one taking no arguments, building each data member with its own default value); once a
constructor is written, this generation stops.

A class can have more than one constructor — as long as their parameter count or type
differs, they are distinguished by the same overload rules as any function. A class can,
by contrast, have only **one** destructor; because a destructor takes no arguments, it
cannot be overloaded.

The biggest difference between a constructor and an ordinary member function is that,
while the constructor is running, the object is **not yet complete**. While
`Quantity(int value)` runs, `value_` is built by the member initializer list's
`value_(value)`; once the body begins running, `value_` already holds a valid value and
can be read inside the body, but until the body runs, the object's other members (this
class has only `value_`, but in a class with more members, the members that follow) may
not yet be built. For this reason, calling another member function through `this` inside
a constructor's body — especially a virtual member function, a topic outside this
course's scope — carries the risk of reaching a not-yet-fully-built state of the object;
this lesson makes no such call.

The destructor's position is symmetric: while the destructor is running, the object is
still complete and valid, but once the destructor returns the object is considered gone
— the memory for its member variables may still physically remain, but the program
accessing it is undefined behavior (a rule this course inherits from M11/K02: undefined
behavior is never run, it is only mentioned in prose). `Quantity::~Quantity`'s body reads
and prints `value_` one last time; no code after that line should access the same
object's `value_`.

```cpp
// quantity.hpp — a constructor, a destructor, and a constructor chain
#ifndef QUANTITY_HPP
#define QUANTITY_HPP

#include <cstdio>

class Quantity {
public:
    Quantity(int value) : value_(value) {
        std::printf("constructor ran value=%d\n", value_);
    }

    ~Quantity() {
        std::printf("destructor ran value=%d\n", value_);
    }

    int value() const { return value_; }

private:
    int value_;
};

#endif
```

**CR5.** `Quantity(int value)` takes an argument, and `: value_(value)`, which runs
before its body, is a **member initializer list** — it builds the data member `value_`
with the value `value` before the body runs. Writing `value_ = value` inside the body
would give the same result here too, but the initializer list separates construction
from assignment: by the time the body runs, `value_` already exists, it is only being
modified.

#### Implicit Construction and explicit

`Quantity(int value)` is a constructor that takes exactly **one** `int` argument; C++
also uses a constructor like this for **implicit type conversion**. If a function like
`show(Quantity q)` is called as `show(5)`, the compiler implicitly calls this
constructor to convert `5` into a `Quantity` — the constructed object has no name, no
variable is visible in `main`, but the object genuinely exists and its constructor
genuinely runs.

```cpp
// temporary-measurement.cpp — is a quantity implicitly built from an int a temporary
#include <cstdio>

#include "quantity.hpp"

static void show(Quantity q) {
    std::printf("inside show value=%d\n", q.value());
}

int main() {
    std::printf("before call\n");
    show(5);
    std::printf("after call\n");
    return 0;
}
```

```text
before call
constructor ran value=5
inside show value=5
destructor ran value=5
after call
```

**CR6.** In the call `show(5)`, `5` is first converted into a `Quantity` object through
`Quantity(5)` — this object has no name, and is therefore **temporary**. This temporary
is copied into `show`'s parameter `q` (or built directly in its place — a compiler
optimization outside this course's scope); when `show` returns, `q`'s destructor is
called, and the output order shows this: the constructor runs right after the call, the
destructor runs right after `show` returns, but **before** the `after call` line — the
temporary's lifetime is bounded by the expression `show(5);` alone, it does not spill
into the rest of `main`.

This implicit conversion is not always wanted: when `show(5)` is written, it is not
obvious to a reader whether `5` is meant to pass as a `Quantity` or is an integer passed
by mistake. The `explicit` keyword prevents this: had `explicit Quantity(int value)`
been written, `show(5)` would not compile, and only an explicit construction such as
`show(Quantity(5))` or `show(Quantity{5})` would compile. This lesson leaves `Quantity`
without `explicit` because what it wants to measure is exactly the temporary that
implicit construction produces; but a class author should consider marking every
single-argument constructor `explicit` — the constructors written in this course's later
lessons are also written as `explicit` unless stated otherwise.

The risk of implicit conversion is not only readability. When a chain of two arguments
allows implicit construction — for example, if `Quantity` implicitly converted from
another class's constructor as well — the compiler could compile a call through an
unexpected chain; the C++ standard limits this by allowing **at most one** implicit
user-defined conversion per call, but even a single-step implicit conversion can hide a
constructor call the reader did not expect. In the `show(5)` example this risk is small,
because `Quantity` has only one constructor and the intent is clear; in a large class
hierarchy, the same implicit construction can silently add the cost of building an
object (a constructor running, a destructor running) that the caller did not notice.
`explicit` removes this silence: every construction is then forced to appear in the
source code as a visible `Type(...)` call.

#### Constructor Chains and Reverse-Order Destruction

In a class with more than one data member, the member initializer list ensures that
members are built in **declaration order** — not the order written in the list, the
order of declaration in the class body governs. Destruction happens in exactly the
opposite order: the member built last is destroyed first.

```cpp
// pair.cpp — the construction and destruction order of more than one member
#include <cstdio>

#include "quantity.hpp"

class Pair {
public:
    Pair() : first_(1), second_(2) {
        std::printf("pair constructor ran\n");
    }

private:
    Quantity first_;
    Quantity second_;
};

int main() {
    std::printf("block started\n");
    {
        Pair p;
        std::printf("pair constructed\n");
    }
    std::printf("block ended\n");
    return 0;
}
```

```text
block started
constructor ran value=1
constructor ran value=2
pair constructor ran
pair constructed
destructor ran value=2
destructor ran value=1
block ended
```

**CR7.** Before `Pair`'s own constructor body runs, `first_` and `second_` are built in
the class body's declaration order (not the order in the member initializer list — here
the two coincide, so no difference is visible, but the order is always determined by
declaration); each build triggers its own `Quantity` constructor, which is why two
separate `constructor ran` lines appear before the `pair constructor ran` line. When `p`
is destroyed as the inner block closes, `Pair`'s own destructor (generated by the
compiler because none is written here, printing nothing) runs first, and then its
members are destroyed in **reverse order**: `second_` first, `first_` after. Construction
and destruction mirror each other.

In M10/K02 (Rust), a value going out of scope ran `Drop`; C++'s destructor answers the
same idea, but the triggering rules differ, and this lesson does not deepen that
comparison.

Declaration order being binding means the member initializer list's **written** order is
ignored — some compilers report as a warning when the list's order does not match the
declaration order, because the two orders differing can mislead a reader: even if the
list were written as `second_(2), first_(1)`, construction order would still put
`first_` first, because `first_` is declared first in the class body. `Pair` writes the
list in the same order as the declaration for this lesson, so the two orders coincide
and no confusion arises — but the rule is always declaration order, never the order
written in the list.

Reverse-order destruction has another consequence: a member's constructor can safely
use a resource built by an earlier member — while `second_` is being built, `first_` is
already fully built, because it precedes it in declaration order. The same guarantee
runs in reverse during destruction: while `second_` is being destroyed, `first_` has not
yet been destroyed, so `second_`'s destructor can, if needed, still safely access
`first_`. This symmetry is the foundation the next lesson's subject, RAII (Resource
Acquisition Is Initialization), is built on: a member holding a resource is not
destroyed before the object holding it goes out of scope.

#### Constructors Calling Each Other

When a class has more than one constructor, one constructor can call another by
**delegating** to it, to avoid duplicating code between them: writing `Quantity() :
Quantity(0) {}` defines a constructor that, when called with no arguments, delegates its
work to the single-argument constructor. Delegation is written by calling the class's own
name in the member initializer list — here `Quantity(0)` calls a constructor of the
class itself, not of another member. The delegated-to constructor runs completely
(including its own body), and the delegating constructor's body runs after it.
`Quantity` does not use delegation within this lesson's scope — it has only one
constructor — but this technique is the standard way to keep shared construction logic
between multiple constructors in a single place; it must not be confused with building a
member in the initializer list, since one calls the class's own name and the other calls
a member's name.

#### The Default Constructor and Default Values

`Quantity` does not write a no-argument constructor, because it wants a quantity to
always be built with a starting value — writing `Quantity t;` does not compile for this
class, because its one constructor requires an `int`. If a class writes no constructor
at all, the compiler generates a no-argument **default constructor**; this generated
constructor builds every data member with its own default value — members of class type
run their own default constructors, while members of primitive types such as `int`
(unless an initializer is given in the member declaration) are left **uninitialized**,
meaning they carry a random memory value. This is a behavior inherited from C and
unchanged in C++: a class like `Pair` that only has members of class type has a safe
default constructor, because every member runs its own constructor; but a member such as
`int amount_;` left without an initializer is left uninitialized by the default
constructor. The classes written in this course give every member of a primitive type an
explicit starting value, either in the declaration (`int amount_ = 0;`) or in the member
initializer list; reading an uninitialized member is also undefined behavior and is not
run.

#### The Bounding Measurement

The expression this lesson measures — the implicitly built `Quantity` inside `show(5)` —
is of kind **temporary**: it has no name, and it ceases to exist at the end of the
expression `show(5);`. But a temporary's lifetime does not always stay this short: a
temporary, if bound to a `const` reference, has its lifetime extended to match the
reference's. Had `const Quantity& r = Quantity(7);` been written, the temporary on the
right would normally cease to exist at the end of the expression, but because it is
bound to `r`, its lifetime is extended to the end of `r`'s scope — the compiler does this
automatically, the programmer writes nothing extra. This extension only applies to
`const` references (and to rvalue references, outside this course's scope); writing
`Quantity& r = Quantity(7);` does not compile, because a non-`const` reference cannot
bind to a temporary. That the reference itself cannot be **rebound** to another temporary
afterward — that a reference, once built, always refers to the same object — is what the
references lesson in the next topic measures.

This boundary explains why temporaries must be used carefully in chains of function
calls: in a call such as `show(Quantity(5))`, the temporary lives only for the duration
of the expression in which `show` runs; if a pointer to the temporary, or a non-`const`
reference to it, is carried out of that expression, that pointer or reference becomes
**dangling** once the expression ends — the memory it points at is no longer valid. That
`Quantity`'s `value()` function returns an `int`, not a `const Quantity&` or a
`Quantity*`, exists exactly to avoid this risk: an `int` is copied as a value, and even
if the temporary itself ceases to exist, the copied value remains valid.

These three rules together — that implicit construction produces a temporary, that
declaration order governs construction and destruction, and that a `const` reference can
extend a temporary's lifetime — show that an object "existing" and an object "being
named" are not the same thing. The `Quantity` inside `show(5)` is built without ever
being assigned to a variable, its constructor runs, it is used, its destructor runs — and
throughout this entire process no name ever points at it. The next lesson's RAII uses
exactly this observation: releasing a resource does not require an object to be named,
only that its lifetime reach its end — the compiler always knows that moment, whether the
object has a name or not.

#### Summary

- The expression this lesson measures is of kind **temporary**: the `Quantity`
  implicitly built inside `show(5)` has no name and ceases to exist at the end of the
  expression `show(5);`.
- A constructor carries the same name as the class; a destructor is written with a `~`
  prefix; a destructor takes no arguments and cannot be overloaded.
- A single-argument constructor allows implicit type conversion; `explicit` prevents
  this and allows only explicit construction.
- The member initializer list builds members in **declaration order**; destruction
  happens in the **reverse** order.
- A temporary bound to a `const` reference has its lifetime extended to match the
  reference's scope.

#### Next Step

This lesson measured when an object comes to exist and ceases to exist; the next lesson
uses that knowledge to safely release a resource (such as memory or a file handle) —
measuring how a destructor releases a member, by separating a guard from the member
inside it.

### RAII

Source: https://academia.sh/en/courses/cpp-fundamentals/raii

Measures that the member a guard acquires and releases is a part inside the guard object, not the guard itself.

The previous lesson measured when an object is constructed and destroyed, whether it has a name or not. This lesson puts that knowledge to a purpose: releasing a resource safely — here a simple counter-like resource, in real programs it could be memory, a file handle, or a lock. The measurement kind this time is **part**: the thing a guard acquires and releases is not the guard itself, but a data member inside it.

#### What RAII Is

**RAII** (Resource Acquisition Is Initialization) is a design pattern that has a resource acquired in an object's constructor and released in its destructor. As long as the object holding the resource is alive, the resource stays valid; when the object — named or temporary, as seen in the previous lesson — reaches the end of its lifetime by any path, the destructor runs and releases the resource. This makes releasing the resource by hand (calling a function like `release()` one by one in every piece of calling code) unnecessary: no matter which path the object holding the resource is destroyed by (reaching the end of a function, an early `return`, throwing an exception), the destructor **always** runs.

RAII's opposite is leaving the resource to the caller's discipline instead of a constructor/destructor pair: an `open_resource()` function is called, used, and a `close_resource()` is expected to be called by hand at every exit point of the code. This approach's fragility shows up as the code grows — when a new early `return` is added to a function, a `close_resource()` call must also be added before that `return`; if it is not added, the resource leaks (leak — the resource stays valid for the rest of the program's run without ever being released). RAII removes this risk by handing the release decision not to the code holding the resource but to the responsibility of **the type of the object holding** it: code that uses `Guard` never writes a release call, because that call is already written once, in the class itself, inside `Resource::~Resource()`. This lesson's first section defines two classes: `Resource`, which actually holds the resource, and `Guard`, which wraps it as a member.

```cpp
// resource.hpp — a simple resource represented by numbers
#ifndef RESOURCE_HPP
#define RESOURCE_HPP

#include <cstdio>

class Resource {
public:
    explicit Resource(int id) : id_(id) {
        std::printf("resource acquired id=%d\n", id_);
    }

    ~Resource() {
        std::printf("resource released id=%d\n", id_);
    }

    int id() const { return id_; }

private:
    int id_;
};

#endif
```

```cpp
// guard.hpp — a guard that acquires and releases the member holding the resource
#ifndef GUARD_HPP
#define GUARD_HPP

#include "resource.hpp"

class Guard {
public:
    explicit Guard(int id) : resource_(id) {}

    int id() const { return resource_.id(); }

private:
    Resource resource_;
};

#endif
```

#### What the Guard Releases Is a Part, Not the Guard Itself

`Guard` has its own constructor and a compiler-generated destructor; when `Guard` constructs its `resource_` member, `Resource`'s constructor runs, and when `Guard` itself is destroyed, `resource_` is destroyed and `Resource`'s destructor runs. The question here: is the thing the guard acquires and releases the `Guard` object itself, or the `resource_` member inside it?

```cpp
// part-measurement.cpp — is the resource the guard holds the guard itself or a part inside it
#include <cstdio>

#include "guard.hpp"

int main() {
    std::printf("block started\n");
    {
        Guard g(7);
        std::printf("id %d\n", g.id());
    }
    std::printf("block ended\n");
    return 0;
}
```

```text
block started
resource acquired id=7
id 7
resource released id=7
block ended
```

**CR8.** `Resource`'s constructor is triggered on the `Guard g(7)` line, before `Guard`'s own constructor body runs, by `resource_(id)` in the member initializer list — this is why the `resource acquired` line is seen right after `block started`, before `Guard`'s own body prints anything. The object that actually acquires the resource is `Resource`, and this object is **not** `Guard` itself but a member of it — `resource_` is a subobject inside `Guard`'s memory range, not a separate, independent object. The proof of this is in the ordering: when `g` is destroyed at the end of the block, `Guard`'s (compiler-generated, printing nothing) destructor runs first, and then, because it is a member of `Guard`, `resource_`'s destructor runs — this is why the `resource released` line is seen before `block ended`. If `resource_` were an independent object separate from `Guard`, its destruction would not depend on `Guard`'s destruction; but here the two are triggered at the same moment, by the closing of the same scope — because one is a part of the other.

There is no name collision to worry about here: `Resource` and `Guard` are each their own class, one holding the other as a member. `Guard`'s own constructor, `explicit Guard(int id) : resource_(id) {}`, has no body — the member initializer list does all the work, constructing `resource_` with `id`. `Guard` has no destructor written of its own; the compiler generates one, and this generated destructor, printing nothing itself, merely triggers `resource_`'s destructor — this is the same behavior seen in the previous lesson's `Pair` example: even when a class writes no destructor of its own, its members' destructors still run.

#### The Destructor Still Runs on Early Exit Paths

RAII's real value is writing the code that releases the resource in a single place (the destructor) and leaving it to the compiler to run that code on **every** exit path — a function's normal end, an early `return`, or even when an exception is thrown.

```cpp
// early-exit.cpp — does the guard still release on an early return path
#include <cstdio>

#include "guard.hpp"

static void run(bool early_exit) {
    Guard g(9);
    std::printf("run started id=%d\n", g.id());
    if (early_exit) {
        std::printf("exiting early\n");
        return;
    }
    std::printf("finishing normally\n");
}

int main() {
    run(true);
    std::printf("main continues\n");
    return 0;
}
```

```text
resource acquired id=9
run started id=9
exiting early
resource released id=9
main continues
```

**CR9.** When `run(true)` reaches the `return` inside the `if` block, `g`'s scope (the function body) ends, and the compiler runs `g`'s destructor **right before the `return`** — this is why the `resource released` line is seen after `exiting early`, but before `main continues`. This behavior is the same regardless of the `if` branch: had `run(false)` been called, the same destructor would still run right after the `finishing normally` line. The code that releases the resource is written only once, inside `Resource::~Resource()`; `run` itself makes no release call at all.

This guarantee holds not only for regular control flow like `if`/`return`, but also for C++'s exception mechanism: if an exception is thrown (`throw`) inside a function body, the stack **unwinds** (stack unwinding) until that exception is caught by a `catch` block — during this unwinding, the destructors of the local objects in each scope being unwound run in order, exactly as with a normal `return`. Had there been a `throw` line after `g` inside `run`, `g`'s destructor would still run before the exception left `run`. This course does not teach throwing and catching exceptions — that is another topic — but RAII's real strength comes from exactly this: the code that releases the resource does not need to know **which** path control flow exits by, because the destructor runs on every path.

#### The Risk of Holding a Resource by Reference

RAII's soundness rests on the guard holding the resource **by value** (as a member, bound to its own lifetime). If a guard holds the resource by reference or pointer, the guard's own lifetime and the resource's real owner's lifetime can diverge — the resource may already be gone while the guard is still alive. `Guard` does not carry this risk because `resource_` is not a reference or a pointer but a direct `Resource` value; as long as `Guard` is alive, `resource_` is alive too, because it is a part of the same object. Had a guard been wrongly designed to hold the resource by pointer instead of by value — something like `Resource* resource_;` — copying the guard would copy only the pointer, not the actual `Resource` object; two guards would point at the same resource, and once one released the resource in its destructor, the other would end up pointing at an invalid resource. This lesson does not run this mistake — it is only mentioned in prose — because releasing a resource twice is undefined behavior.

Solving this sharing problem with the standard library's ready-made RAII wrappers is K05's subject; this course manages the resource with classes it writes itself. M10/K02's (Rust) ownership system and M11/K02's resource management are that same idea's — that a resource has exactly one owner, and the resource is released automatically once the owner's lifetime ends — counterparts in different languages; this lesson does not deepen that comparison.

It is useful to see in more detail how `Guard`'s own design avoids this risk. `resource_` **is** a `Resource` value, not a `Resource*` or a `Resource&`; this is why `resource_` itself (not merely an address pointing at it) sits in the `Guard` object's memory layout. When a `Guard` is copied — this course's next lesson's subject — `resource_` is copied too, because it too is a part of `Guard`; two `Guard`s carry two separate `Resource`s, not sharing the same resource. This is not true for a resource held by pointer: copying the pointer copies only the address, not the pointed-to object, so two guards begin pointing at the same resource. This consequence of holding by value — that copying also copies the resource along with it — is a part of RAII's reliability and is measured in detail in the next lesson.

Holding a resource by value has a limit too: because the resource sits in the holding object's memory layout, the resource's size (or at least the size of the handle representing it) must be known at compile time. This problem does not show up here because `Resource` carries only an `int`; a real resource — an open file, a network connection — is usually represented by a fixed-size handle given by the operating system (for example an integer or a pointer), which is why the same hold-by-value strategy works for real resources too.

#### A Guard Holding More Than One Resource

A guard holding more than one resource instead of a single one follows the same rule: each resource becomes another member of the guard, and each member's construction/destruction order follows the declaration-order rule measured in the previous lesson. Had a `DoubleGuard` with two `Resource` members been designed, the members would be constructed in declaration order and destroyed in reverse order — exactly like `first_`/`second_` in the `Pair` example. This lesson does not run `DoubleGuard`, because acquiring and releasing a single resource is enough to show RAII's core idea; but it is important to see that this generalization comes directly from the previous lesson — RAII adds no new language rule, it merely puts the constructor/destructor order to a purpose.

#### The Bounding Measurement

The expression this lesson measures is of the **part** kind: `resource_` is not `Guard` itself but a subobject inside it, and it has the same lifetime as `Guard`. But RAII's guarantee depends on the guard **holding the resource by value** — if a guard holds only a reference to the resource (the resource's real owner being some other object), the guard must **not outlive** the protected object; if the protected object is destroyed while the guard is still alive, the guard's reference becomes dangling, and the guard's destructor (if it has one) may try to access an invalid object. This lesson does not run this risk, because running it would trigger undefined behavior; `Guard` here always holds the resource by value, so this risk does not exist to begin with.

A practical consequence of this bound is that when designing a guard, the question "who really owns this resource" must always be answered explicitly. In `Guard` the answer is clear: `Guard` itself owns it, because `resource_` is a value member of it. Had a guard instead wanted to say "I am only observing a resource living elsewhere" — for example wanting to store a `Resource&` taken as a function parameter — this would no longer be RAII, only holding a reference, and the responsibility of releasing the resource would not belong to the guard. Both designs are valid in C++, but they must not be confused with each other: a class's destructor must release only the resources **it itself owns**, not one it has merely borrowed.

The three examples measured throughout this lesson — the proof of construction order, the destructor running on early exit, holding the resource by value — together show why RAII is more than a "best practice": it is a direct consequence of the language's constructor/destructor and declaration-order rules, not a separate mechanism. The next lesson's copying question is also built on this same foundation — when a `Guard` is copied, `resource_` will be copied too, but whether this copy is "deep" or "shallow" can produce different results depending on the resource's type.

#### Summary

- The expression this lesson measures is of the **part** kind: `resource_` is not the `Guard` object itself, but a subobject inside it.
- RAII acquires a resource in the constructor and releases it in the destructor; no code that releases the resource by hand is needed.
- The destructor runs regardless of how the scope ends — a normal end, an early `return`, or throwing an exception, it is the same in all of them.
- A guard that holds the resource **by value** binds the guard's lifetime to the resource's lifetime; a guard that holds it by reference loses this guarantee.
- Smart pointers extend RAII to shared resources; this is outside this course's scope (K05).

#### Next Step

This lesson measured how a resource is safely held by a constructor/destructor pair; the next lesson asks what this guarantee becomes when an object is **copied** — it measures whether the copy constructor acquires its own resource, or shares the original's.

### Copying and Assignment

Source: https://academia.sh/en/courses/cpp-fundamentals/copying-and-assignment

Measures that the copy constructor and copy assignment operator produce a deep copy that takes its own array, and that the depth of the copy depends on the design of the class.

The previous lesson claimed that a guard holds its resource by value, so when the guard is
copied, its resource is copied along with it. This lesson measures that claim: when an
object is copied, does the copy share the same memory as the original, or does it take its
own memory? The measurement kind is **copy**: `b`, constructed from `a` with
`Buffer b(a)`, is a newly constructed object, different from `a` — but how deep that
"different" runs depends on how the class's copy constructor is written.

In C, copying an array was always an **explicit** operation: `memcpy` is called by hand,
the destination being large enough is checked by hand, and the source and destination not
overlapping is guaranteed by hand. In C++, when a class object is copied via `=` or passed
by value as an argument, the copying is **implicit** — the compiler decides on its own which
function to call, no explicit call is written by hand. This makes copying easier, but it
also hides it: seeing a line like `Buffer b(a);` and understanding how much work it does
(allocating new memory, copying element by element) requires looking at the class's
definition — the line itself does not say.

#### Copy Constructor and Copy Assignment

A class's **copy constructor** is a constructor that takes a `const&` of the same class —
`Buffer(const Buffer& other)`. This constructor is called during a **construction**, as in
`Buffer b(a);` or `Buffer b = a;`: `b` does not yet exist, and is constructed from `a`.
**Copy assignment**, on the other hand, is an overload of `operator=` —
`Buffer& operator=(const Buffer& other)`. This is called during an **assignment**, as in
`b = a;`: `b` already exists (it was constructed earlier), and only its value is replaced
with `a`'s. Both take `const Buffer&` as their argument type, but one constructs a new
object while the other changes the contents of an existing object — this difference is what
determines which one is called: whether the object on the left is new or already existing.

This distinction is not merely syntactic. While the copy constructor is running, the
object's data members are not yet **constructed** — the same rule from the third lesson's
member initializer list applies here too: `data_(new int[other.size_])` initializes the
member for the first time. While copy assignment is running, on the other hand, the object
is already constructed, and `data_` already points at a valid array — this is why
`operator=` **must** first release the old array (`delete[] data_`); otherwise the old array
is never freed while a new one is assigned over it, which is a memory leak. The copy
constructor has no such prior state, because the object does not yet exist — this is why the
copy constructor never calls `delete[]`, it only allocates.

```cpp
// buffer.hpp — a class holding its own array, copying deeply
#ifndef BUFFER_HPP
#define BUFFER_HPP

#include <cstdio>

class Buffer {
public:
    explicit Buffer(int size) : size_(size), data_(new int[size]) {
        for (int i = 0; i < size_; ++i) {
            data_[i] = i;
        }
        std::printf("constructor ran size=%d\n", size_);
    }

    Buffer(const Buffer& other) : size_(other.size_), data_(new int[other.size_]) {
        for (int i = 0; i < size_; ++i) {
            data_[i] = other.data_[i];
        }
        std::printf("copy constructor ran size=%d\n", size_);
    }

    Buffer& operator=(const Buffer& other) {
        if (this == &other) {
            return *this;
        }
        delete[] data_;
        size_ = other.size_;
        data_ = new int[size_];
        for (int i = 0; i < size_; ++i) {
            data_[i] = other.data_[i];
        }
        std::printf("copy assignment ran size=%d\n", size_);
        return *this;
    }

    ~Buffer() {
        delete[] data_;
    }

    int first_element() const { return data_[0]; }
    void set_first_element(int value) { data_[0] = value; }
    const int* address() const { return data_; }

private:
    int size_;
    int* data_;
};

#endif
```

#### A Deep Copy Takes Its Own Array

```cpp
// copy-measurement.cpp — is b, freshly constructed from a, a copy that takes its own array
#include <cstdio>

#include "buffer.hpp"

int main() {
    Buffer a(3);
    Buffer b(a);

    std::printf("do a and b share an array %s\n", a.address() == b.address() ? "yes" : "no");

    b.set_first_element(99);
    std::printf("a first element %d\n", a.first_element());
    std::printf("b first element %d\n", b.first_element());
    return 0;
}
```

```text
constructor ran size=3
copy constructor ran size=3
do a and b share an array no
a first element 0
b first element 99
```

**CR10.** `Buffer b(a);` constructs `b` from `a` with the copy constructor; the copy
constructor reads `other.size_` and allocates a separate array with its **own** call to
`new int[other.size_]`, then copies `other.data_`'s elements into this new array one by
one. This is a **deep copy**: `b.data_` and `a.data_` are different addresses,
`a.address() == b.address()` prints `no`. This is why `b.set_first_element(99)` changes
only `b`'s own array; `a.first_element()` is still `0`. `b` is of kind **copy** relative to
`a`: newly constructed, different from `a` in address, but equal to it in the value it held
at the moment of construction.

#### Copy Assignment and the Self-Assignment Check

```cpp
// assignment-measurement.cpp — does b = a run copy assignment
#include <cstdio>

#include "buffer.hpp"

int main() {
    Buffer a(2);
    Buffer b(5);

    b.set_first_element(-1);
    a.set_first_element(42);
    b = a;
    std::printf("after assignment is b's first element the same as a's %s\n",
                b.first_element() == a.first_element() ? "yes" : "no");
    std::printf("do a and b share an array %s\n", a.address() == b.address() ? "yes" : "no");

    b = b;
    std::printf("after self-assignment is b still valid %s\n", b.first_element() == a.first_element() ? "yes" : "no");
    return 0;
}
```

```text
constructor ran size=2
constructor ran size=5
copy assignment ran size=2
after assignment is b's first element the same as a's yes
do a and b share an array no
after self-assignment is b still valid yes
```

**CR11.** In the line `b = a;`, `b` is already a constructed object, so copy assignment is
called, not the copy constructor. `operator=` first releases `b`'s **old** array with
`delete[] data_`, then allocates a new array of the same length as `a`'s and copies
`a.data_`'s contents into it — this is why, after the assignment, `b`'s first element
equals `a`'s (the contents were copied), but `b.address()` is **not** equal to
`a.address()` (a new array was allocated, not shared). `b`'s address before the assignment
is not separately printed and compared here: whether the `new` that immediately follows the
`delete[]` returns the same address depends on the allocator, and the C++ standard does not
guarantee this — so such a comparison would not count as evidence, only the contents and
the not-shared-with-`a` state are measured. The line `b = b;` triggers the
`if (this == &other) return *this;` check at the start of `operator=`: without this check,
the function would first release `b`'s own array with `delete[]`, then try to read
`other.data_` (which is now the same, already-released, invalid address) — this would be
undefined behavior. Thanks to the check, `b = b;` safely returns early, and `b` remains
unchanged.

#### The Risk of a Shallow Copy, and the Rule of Three

If `Buffer`'s copy constructor and copy assignment operator were not written by hand, the
compiler would use its own generated default versions — these copy every data member
**member by member**. Because `size_` is an `int`, this causes no problem, but `data_` is an
`int*`; member-by-member copying copies the pointer itself, not the array it points at.
This is a **shallow copy**: two `Buffer`s would share the same `data_` address. The result of
a shallow copy is this — when one is destroyed, it runs `delete[] data_`, while the other
still points at the same (now released) array; when that object is also destroyed, it tries
to release the same array again with `delete[]`. This **double free** is undefined
behavior, and this lesson does not run it — it is only mentioned in prose; `Buffer` is
always run with the hand-written deep copy constructor and assignment.

This observation leads to the **rule of three**: if a class has to write its destructor,
copy constructor, or copy assignment operator by hand (usually because it holds a resource
through a raw pointer), it must write all three by hand — if one is written by hand and the
other two are left to the compiler, the risk of a shallow copy arises. `Buffer` fully
applies this rule: the destructor, the copy constructor, and copy assignment, all three
manage `data_` correctly.

There is a reason the rule is limited to "three": all three are different faces of the same
problem — ownership of the resource. The destructor defines when the resource is released,
the copy constructor defines how the resource is duplicated, and copy assignment defines
how an existing resource is changed. If one is forgotten (for example, only the destructor
is written and the copy constructor is left to the compiler), the compiler-generated
shallow copy constructor shares `data_` — then two objects each try to release the same
array with `delete[]`, which is a double free. The mere existence of a destructor is itself
a sign that the other two must also be written by hand: if a class does something special in
its destructor (something beyond just `delete[]`), this usually means the class is the
**owner** of a resource, and ownership must also be thought through during copying.

#### Preventing Copying with `= delete`

Not every class needs to be copyable. If a resource is meant to have a single owner — for
example, a file handle or a network connection should not be shared with a second object —
the copy constructor and copy assignment can be explicitly **deleted** with `= delete`:
`Buffer(const Buffer&) = delete;`. This does not tell the compiler to never generate that
function, but to give a compile error when it is used — code that tries to write
`Buffer b(a);` does not compile. `Buffer` remains copyable for this lesson's measurement,
`= delete` is only mentioned here; which classes should be designed as non-copyable, and how
that decision relates to the ownership model, is K05's topic.

#### Why the Copy Constructor's Argument Is `const&`

The copy constructor's argument is taken as `const Buffer&`, not as `Buffer`. If the
argument were taken by value (`Buffer other`), calling the function would itself require a
copy of `other` — and the function that would construct that copy would be the copy
constructor itself, an infinite loop. Taking it by reference breaks this loop: the original
object is accessed directly, with no extra copy produced. `const`, meanwhile, guarantees
that `other` will only be read, not modified during the copy — the copy constructor must
not modify its source, only read from it.

#### A Copy Does Not Reveal the Depth of the Source

Like the `Guard` from the previous lesson, `Buffer` also holds its resource by value — but
while `Guard`'s `resource_` member is a `Resource` **value**, `Buffer`'s `data_` member is
an `int*`; the resource (the array) lives on the heap, and the member is only a pointer to
it. This lesson closes that gap by writing `Buffer` **by hand** to copy deeply, but the
depth of a copy is never automatic — it depends on what the class's copy constructor
writes. If a class is tied to a record shared through a raw pointer (for example, if the
`int*` only points at an array owned by another object, and ownership is not with
`Buffer`), member-by-member copying also copies this pointer, and the copy shares the same
record as the original — a deep copy only happens when the class is the **owner** of its
own resource, and the copy constructor explicitly reallocates it.

This means that different members of the same class can call for different copying
behavior. If `Buffer` also had a member named `const int* reference_`, pointing at a
resource it does not own, it would be correct for the copy constructor to **deliberately**
copy this member shallowly — copying the pointer as it is, without allocating new memory —
because `Buffer` is not the owner of that resource, it only looks at it. The question that
must be asked when writing a copy constructor is this: is this member a resource this
object owns, or only a resource it looks at? The answer can differ from member to member,
and the copy constructor's body is the sum of these decisions — the compiler-generated
default member-by-member copy never makes this distinction, it copies every member the same
way (shallowly).

Move — a resource being transferred by **taking it over** rather than by copying it —
solves this problem in a different way, and is outside this course's scope (K05). M11/K01
covered a struct being copied whole, field by field, through assignment, and memory
layout — member order, alignment, and padding; this lesson combines the two: copying
conforms both to value semantics (a copy is independent of the original) and to memory
management (a copy takes its own memory) at the same time.

#### The Bounding Measurement

The expression this lesson measures is of kind **copy**: `b` is newly constructed from `a`,
an object separate from `a` in address. But a copy does not, by itself, say how "deep" it
is — this information is not in the result of the copy, it is hidden in how the class's
copy constructor behaves with its source. `Buffer` copies deeply because its copy
constructor allocates a new array with `new int[...]`; a class tied to a resource through a
raw pointer, one that has not written its own copy constructor correctly, copies shallowly,
and the copy shares the same resource as the original. To read a class and answer the
question "can this be copied, and what happens when it is copied," you have to look at the
body of the copy constructor — the class's name or the way it is used does not say.

#### Summary

- The expression this lesson measures is of kind **copy**: `Buffer b(a)` is newly
  constructed from `a`, an object separate from it in address.
- The copy constructor is called during a **construction**, copy assignment during an
  **assignment**; whether the object on the left is new or already existing determines
  which one runs.
- `Buffer` produces a **deep copy** by allocating its own array with `new`; member-by-member
  copying would only copy the pointer, which would be a **shallow copy**.
- Copy assignment safely handles **self-assignment** with the `this == &other` check.
- If one of the destructor, the copy constructor, or copy assignment is written by hand, all
  three must be written (the rule of three).

#### Next Step

This lesson measured that an object takes its own resource when it is copied; the next
lesson moves away from copying and measures how a **reference** directly modifies the
caller's object — producing no copy at all.

### References

Source: https://academia.sh/en/courses/cpp-fundamentals/references

Measures that a reference parameter works with the caller's own object, producing no copy at all.

The previous lesson measured that an object takes its own memory when it is copied. This
lesson measures the exact opposite question: if a function takes an object **by
reference**, is any copy produced at all, or does the function work directly with the
caller's own object? The measurement kind is **self**: when `p` is given to the function
`nudge(Point& n)`, the `n` inside the function and the `p` in the caller are the same
object — `&p == &n` is true, and no copying step happens between them.

In C, the only way to pass a struct to a function "by reference" was to pass a pointer:
`nudge(&p)`, accessed inside the function with `(*ptr).x` or `ptr->x`. This forced the
`&` operator to be written by hand at the call site, and forced a dereference (`*`) or
the arrow operator to be written at every access inside the function — and there was
always a possibility that `ptr` was `nullptr`. In C++ a reference removes both problems
at once: `nudge(p)` is written at the call site, no `&` is needed; `n.x` is written
inside the function, no dereference is needed; and because a reference cannot be left
uninitialized, the `nullptr` case is ruled out by the language itself.

#### What a Reference Is

A **reference** is a second name given to an existing object — it is not a new object,
and it does not get a new memory address. When `Point& r = p;` is written, `r` is `p`
itself; every read and write made through `r` reaches `p`'s memory directly. This is
different from a pointer (`Point* ptr = &p;`): a pointer is a separate object, has its
own memory, and **holds** `p`'s address; a reference, on the other hand, is the **same**
thing as `p` itself, and occupies no separate memory location (the compiler often turns
a reference into a pointer in the generated code, but in the language's own model a
reference is not a new object).

The practical consequence of this distinction is this: a pointer does not guarantee,
before `ptr->x` is written, that it points at a valid object — it may need to be checked
by hand (`if (ptr != nullptr)`). There is no such check for a reference, and none is
needed — the language assumes that a reference is always bound to a valid object (code
that deliberately breaks this assumption, for example by dereferencing an invalid
pointer and binding it to a reference, produces undefined behavior, but no code within
this lesson's scope does anything like that). This is why a function signature that
takes a reference requires less defensive code than one that takes a pointer — the
existence of the parameter is accepted from the start.

```cpp
// point.hpp — a simple struct for measuring passage by reference
#ifndef POINT_HPP
#define POINT_HPP

struct Point {
    int x;
    int y;
};

#endif
```

#### A Struct Passed by Reference

```cpp
// reference-measurement.cpp — does nudge(Point&) work with the caller's own object
#include <cstdio>

#include "point.hpp"

void nudge(Point& n, Point* caller_address) {
    std::printf("is n inside nudge the same object as the caller %s\n",
                &n == caller_address ? "yes" : "no");
    n.x += 10;
    n.y += 10;
}

int main() {
    Point p{1, 2};

    nudge(p, &p);

    std::printf("after nudge p.x=%d p.y=%d\n", p.x, p.y);
    return 0;
}
```

```text
is n inside nudge the same object as the caller yes
after nudge p.x=11 p.y=12
```

**CR12.** `nudge(Point& n, Point* caller_address)` takes its argument by reference; when
`nudge(p, &p)` is called, `n` is `p` **itself** — `&n == caller_address` (that is,
`&n == &p`) is true. Although the line `n.x += 10;` writes through `n`, because `n` and
`p` are the same object this write directly changes `p.x`; after `nudge` returns, `p.x`
and `p.y` are already updated (`11` and `12`) — `main` continues with the caller's
object changed, without receiving any return value and without performing any
assignment. This is the exact opposite of the previous lesson's **copy** kind: there,
`b` was a different address from `a`; here, `n` is the **same** address as `p` — no
copying step runs at all, because passing a reference argument never calls the copy
constructor.

#### Value, Reference, const Reference: Which One, When

A function has three options when it takes an object as an argument, and each one
encodes a different intent:

- **By value** (`Point n`): the function works with its own copy, and never affects the
  caller's object in any way. This suits small, cheaply copied types (an `int`, a
  `Point` of two `int`s); for large or expensively copied types (a class managing its
  own memory, like `Buffer` in the third lesson), it produces a needless copy on every
  call.
- **By reference** (`Point& n`): the function works directly with the caller's object,
  and can **modify** it. `nudge` does this — its signature tells the reader "this
  function can modify the object you give it."
- **By const reference** (`const Point& n`): the function accesses the caller's object
  without copying it, but **cannot modify it** — `n.x += 10;` would be a compile error
  here. This encodes the intent "read a large object cheaply, but do not modify it";
  this is exactly why the copy constructor's and copy assignment's argument in the
  previous lessons was `const Buffer&`.

The intent is understood by reading the signature: `void write(const Point& n)` only
reads the caller's object; `void nudge(Point& n)` modifies it; `void copy(Point n)`
never touches it at all, and works on its own copy.

There is no shortcut among these three options like "always use a reference, it is
faster." Taking a small type that fits in a single machine word, like `int`, by
reference generally gains nothing — passing a reference also generally means (depending
on the code the compiler produces) passing an address, and an address is typically the
same size as an `int`; moreover, because a function taking a reference can now modify
the caller's object, even a read-only use is left open to an accidental write (this risk
is closed by `const int&`, but then no gain remains either). Taking small types by value
is both simpler and, in most cases, equally fast. The real gain from reference and const
reference appears for types that are expensive to copy — classes that allocate their own
memory, like `Buffer` in the third and fifth lessons, or large structs with many
members.

#### Reference Parameters and Return Values

A reference can be used not only for parameters but also for return types. A function
like `Point& first(Point array[])` can return the array's first element **as itself,
not as a copy** — the caller can write `first(d) = Point{0, 0};` and directly change the
array's first element, because the return value is `d[0]` itself. This lesson does not
run a reference return value (this is the typical usage of overloaded operators such as
`operator[]`, and is covered in K05), but it rests on the same principle as parameter
references: returning a reference is granting access to an existing object without
constructing a new one.

#### Reference Arguments in Member Functions

This principle works the same way for member functions too. The fifth lesson's
`Buffer::operator=` signature was `Buffer& operator=(const Buffer& other)` — the `other`
parameter here, too, is the caller's own object; when `b = a;` is written, `other`
inside `operator=` is the same address as `a`. Every line where `operator=` reads
`other.data_` reads `a`'s memory directly; if `other` had been taken by value (as
`Buffer other`), every `b = a;` call would first build a `Buffer` copy, and `operator=`
would work with that copy — meaning both a needless copy constructor call and a
needless destructor call. The choice of `const Buffer&` carries the same intent here
too: read `a` without copying it, do not modify it.

#### A Reference Cannot Be Rebound

Once a pointer is set, it can be changed to point at a different object:
`ptr = &another;`. This is not possible for a reference — after `Point& r = p;` is
written, `r = another;` is not a rebinding; it **assigns** `another`'s value onto `r`
(that is, onto `p`). Which object a reference is bound to is fixed the moment the
reference is created, and this binding never changes for the reference's lifetime —
this is why a reference must be initialized **at the moment it is created**; there is
no such thing as an empty reference (unlike a pointer's `nullptr`).

#### Binding a const Reference to a Temporary

```cpp
// temporary-binding-measurement.cpp — can a const reference bind to a temporary
#include <cstdio>

#include "point.hpp"

void write(const Point& n) {
    std::printf("inside write x=%d y=%d\n", n.x, n.y);
}

int main() {
    Point p{1, 2};
    write(p);

    const Point& r = Point{3, 4};
    std::printf("via the temporary x=%d y=%d\n", r.x, r.y);

    write(Point{5, 6});
    return 0;
}
```

```text
inside write x=1 y=2
via the temporary x=3 y=4
inside write x=5 y=6
```

**CR13.** The line `const Point& r = Point{3, 4};` binds a `const` reference to a
**temporary** object (`Point{3, 4}`, an unnamed value constructed in the middle of the
expression). Normally a temporary's lifetime ends at the end of the expression that
constructs it, but when it is bound to a `const` reference the C++ standard **extends**
that temporary's lifetime to match the reference's lifetime — as long as `r` is valid,
`Point{3, 4}` is also valid, so reading `r.x` and `r.y` is not undefined behavior. If
the same binding had been written as `Point& r = Point{3, 4};` (without const), it
would not compile: an ordinary reference cannot bind to a temporary, because allowing a
write through the temporary (like `r.x = 99;`) would mean modifying an object the
caller could never see, one that is about to disappear immediately — the language rules
this out from the start as meaningless. The call `write(Point{5, 6})` uses the same
rule: because `write`'s parameter is `const Point&`, the temporary can bind directly;
if the parameter were an ordinary `Point&`, this call would not compile.

#### References and Memory Layout

M11/K01 covered a struct's memory layout — member order, alignment, and padding. A
reference does not establish a "new memory layout" in that lesson's sense — when
`Point& r = p;` is written, `r` has no `sizeof` value or memory layout of its own,
because `r` is not a new object, it is another name for `p`. A class with a reference
member (a member like `Point& reference_;`) may look like an exception to this rule —
such a member typically occupies the space of a pointer, because the compiler turns it
into code that way — but this is an implementation detail; the language itself does not
define "where" a reference is kept, only which object it is bound to.

#### The Bounding Measurement

The expression this lesson measures is of kind **self** — but only in some cases. A
parameter taking `const Point&` can be either **self** or **temporary**; the signature
itself does not say which one, only the argument at the call site determines it.

```cpp
// self-or-temporary.cpp — which kind does a const reference parameter fall under, in each case
#include <cstdio>

#include "point.hpp"

void write(const Point& n) {
    std::printf("inside write x=%d y=%d\n", n.x, n.y);
}

int main() {
    Point p{7, 8};

    write(p);
    write(Point{9, 10});

    std::printf("did p stay unchanged %s\n", (p.x == 7 && p.y == 8) ? "yes" : "no");
    return 0;
}
```

```text
inside write x=7 y=8
inside write x=9 y=10
did p stay unchanged yes
```

**CR14.** In the call `write(p)`, `n` is `p` itself — kind **self**; in the call
`write(Point{9, 10})`, `n` is bound to an unnamed temporary constructed in the middle
of the expression — kind **temporary**. Both calls use the same signature
(`const Point&`) and call the same function, but which kind the parameter falls under
is determined only by the argument itself at the call site. Being `const` prevents the
function from writing through `n` in both cases — this is why `p` remains unchanged on
the third line; whether `write`'s `n` is self or temporary has no effect on `p`'s state
at all. It is not possible to give a definite answer to "is this parameter self" by
looking at a function signature alone — the signature only answers the question **can
it be modified** (reference or const reference); the answer to whether it is self or
temporary is determined anew at each call.

This limit produces a consequence worth considering when designing a class: seeing that
a function accepts a `const Point&` parameter does not guarantee that the function will
always be called with a persistent object. The function body must assume that the
reference it receives may have a lifetime that ends at the close of the call
expression — for example, storing `n`'s address somewhere and using it after the
function returns (something like `Point* p = &n; return p;`) produces a dangling
pointer if `n` is bound to a temporary. This lesson does not run such code; it only
states the limit. The reason the next lesson's `operator+` returns a **new object**
rather than a reference comes from the same limit: the sum the operator produces is a
local value constructed inside the operator's own body, and if it needs to live on
after the function returns, it must be returned by value, not by reference.

#### Summary

- A reference is a second name given to an existing object; it does not construct a new
  object, and does not take a new address.
- An argument taken by reference is the caller's **self** — no copying step runs,
  `&n == &p` is true.
- The choice among value, reference, and const reference encodes intent:
  copy-and-do-not-touch, modify, or read-without-copying-but-do-not-modify.
- Once a reference is created, it cannot be rebound to a different object.
- A `const` reference can bind to a temporary (the temporary's lifetime is extended);
  an ordinary reference cannot.
- A parameter taking `const Point&` can be either **self** or **temporary** depending
  on the call; the signature alone does not say which.

#### Next Step

This lesson measured that a reference works directly with the caller's object, without
copying; the next and final lesson measures why an operator (`operator+`) returns a new
**temporary**, and why `operator+=` instead returns `*this` by reference.

### Operator Overloading

Source: https://academia.sh/en/courses/cpp-fundamentals/operator-overloading

Measures why operator+ returns a new temporary object, and why operator+= instead returns its own object by reference.

This is the last lesson in this section of K04. The previous lesson measured that a reference works with the caller's own object without producing any copy. This lesson measures that an **operator** sometimes does exactly the opposite — it produces a new object. The measurement kind is **temporary**: the result of the expression `a + b` is neither `a` nor `b`; it is a new `Money` object, constructed inside the operator's body, that ceases to exist at the end of the expression.

In C, the only way to add such values was a function with an explicit name: a function like `Money add_up(Money a, Money b)` was called, and its result was assigned to a separate variable — writing `a + b` was not possible, because `+` was defined only for the built-in numeric types. In C++, overloading `operator+` opens up the `+` syntax for a user-defined type like `Money` too; the caller writes `a + b` instead of `add_up(a, b)`. This increases the readability of the syntax, but it also hides what the body does (whether it constructs a new object or modifies an existing one) — this is exactly what this lesson's measurement uncovers: which object is produced behind the operator's syntax.

#### What Operator Overloading Is

**Operator overloading** is defining what a built-in operator such as `+`, `==`, or `<<` means for a user-defined class. When `operator+` is written as a member function, the expression `a + b` is read by the compiler as `a.operator+(b)` — the syntax stays `+`, but what gets called is a function the class itself writes. Overloading does not add a new syntax; it **gives meaning** to the existing operator syntax for user-defined types.

Overloading cannot change how **many arguments** an operator takes, or its **precedence** — `+` always stays binary, and it continues to be evaluated after `*`. The only thing that can change is what the operator does with its arguments. This limit is deliberate: someone calling `operator+` expects the "takes two values and produces a result" behavior for `Money`, just as for `int`; overloading cannot make a syntactic change that breaks this expectation, it can only define what the "result" and "modification" part means.

```cpp
// money.hpp — a class holding an amount in cents, for operator overloading
#ifndef MONEY_HPP
#define MONEY_HPP

#include <cstdio>

class Money {
public:
    explicit Money(long cents) : cents_(cents) {}

    Money operator+(const Money& other) const {
        return Money(cents_ + other.cents_);
    }

    Money& operator+=(const Money& other) {
        cents_ += other.cents_;
        return *this;
    }

    bool operator==(const Money& other) const {
        return cents_ == other.cents_;
    }

    long cents() const { return cents_; }

private:
    long cents_;
};

inline void use_money(const Money& m) {
    std::printf("cents=%ld\n", m.cents());
}

#endif
```

#### `operator+`: Returns a New Temporary

```cpp
// plus-measurement.cpp — is the result of a + b a new temporary
#include <cstdio>

#include "money.hpp"

int main() {
    Money a(100);
    Money b(250);

    Money c = a + b;

    std::printf("is c the same object as a %s\n", &c == &a ? "yes" : "no");
    std::printf("is c the same object as b %s\n", &c == &b ? "yes" : "no");
    use_money(a);
    use_money(b);
    use_money(c);
    return 0;
}
```

```text
is c the same object as a no
is c the same object as b no
cents=100
cents=250
cents=350
```

**CR15.** The expression `a + b` turns into the call `a.operator+(b)`; the body of `operator+`, `return Money(cents_ + other.cents_);`, constructs a **new** `Money` and returns it **by value** — it modifies neither `a` nor `b`, and both keep their own `cents_` value (`100` and `250`). The returned object is constructed into `c`; `c`'s address is neither the same as `a`'s nor as `b`'s. `operator+` being marked `const` (`operator+(const Money& other) const`) guarantees that neither `other` nor the object it is called on (`this`) is modified — by definition, an addition operator must produce only the result, not the operands being added.

#### `operator+=`: Modifies Its Own Object and Returns It by Reference

```cpp
// plus-equals-measurement.cpp — does a += b modify a itself
#include <cstdio>

#include "money.hpp"

int main() {
    Money a(100);
    Money b(250);

    Money& result = (a += b);

    std::printf("is result the same object as a %s\n", &result == &a ? "yes" : "no");
    use_money(a);
    return 0;
}
```

```text
is result the same object as a yes
cents=350
```

**CR16.** The body of `operator+=`, `cents_ += other.cents_;`, modifies its **own** `cents_` member, then `return *this;` returns **itself** by reference — it constructs no new object. When `a += b` is called, `a` itself changes (it becomes `350`), and the result of `(a += b)` is again `a` itself: `&result == &a` is true. This is the exact opposite of `operator+`: `operator+` produces a new **temporary** without modifying either operand, while `operator+=` modifies a single object (the left one) and returns a reference of kind **self**. The two operators' return types carry this difference in their signature — `operator+` returns by value (`Money`), `operator+=` by reference (`Money&`); reading the signature alone tells in advance which one produces a new object and which one modifies an existing one.

#### The Limits of Defining a Meaningful Operator

The fact that an operator can be overloaded for a user-defined class does not mean every class must define every operator. A few conventions keep operator definitions consistent:

- **Binary arithmetic operators like `+`, `-`, `*`** are usually written as **free functions**, not members (`Money operator+(const Money& a, const Money& b)`), because this provides symmetric conversion for expressions whose left side is not `Money` either (for example, if an `int` were to be added to a `Money` in the future). `Money` defines `operator+` as a member for this lesson's measurement; the free-function form is only mentioned here.
- **`+` can be written in terms of `+=`**: instead of `cents_ + other.cents_`, the body of `operator+` could also be written as `Money result(cents_); result += other; return result;` — basing `+` on `+=` without repeating `+=`'s logic prevents the two operators' behavior from drifting apart. `Money` writes the two independently to keep this lesson's measurement simple.
- **`==` is an equality**, not an ordering; `Money::operator==` compares the two objects' `cents_` values, and an ordering operator like `<` is not defined in this lesson.
- **`<<` (stream output) cannot be a member function** — in the expression `std::cout << m`, the left side is `std::ostream`, not `Money`; that is why `operator<<` is written as a free function, and if it needs to access `Money`'s `private` member, access is granted with a `friend` declaration (mentioned only by name in lesson 02). This lesson does not define `operator<<`; it does the same job with an ordinary function named `use_money`.

The question that must be asked when overloading an operator is this: does this operator's built-in meaning (`+` adds, `==` compares, `<<` prints) still feel **natural** for the class? For `Money`, `+` meaningfully matches addition and `==` meaningfully matches equality; but, for example, `Money operator*(const Money& a, const Money& b)` could be left undefined, because multiplying two amounts has no monetary meaning — this lesson does not write such an operator.

Violating this limit compiles, but it makes the code unreadable. C++ enforces no rule about which meaning an operator must be used with — technically, a subtraction could be written into the body of `operator+`, and the compiler would not object. But such code separates what everyone who writes `a + b` expects ("it is adding") from what actually happens ("it is subtracting") — this is a design flaw that misleads the class's user, and its error cannot be caught at compile time. The only thing that limits the power of overloading is not the compiler, but the discipline of staying faithful to the expectation an operator raises in the reader.

#### Where `explicit`, the Copy Constructor, and Operators Meet

`Money`'s constructor is defined as `explicit Money(long cents)` — the `explicit` rule from lesson 03 applies here too: an implicit conversion like `Money m = 100;` does not compile, and `Money m(100);` or `Money m{100};` must be written instead. This interacts directly with operator overloading: the line `return Money(cents_ + other.cents_);` inside `operator+`'s body writes an **explicit** construction; if the constructor were not `explicit` and the body wrote `return cents_ + other.cents_;`, the `long` result could be implicitly converted into a `Money` — this would open the door to exactly the kind of unwanted implicit conversion chain lesson 03 warned about (for example, a `Money` being compared, indirectly and by mistake, with a `long`). `operator+`'s result is always returned by explicitly constructing a `Money`; this both follows the `explicit` rule and keeps what the operator produces explicit in the code. The copy constructor from lesson 05 also comes into play here implicitly: when the line `return Money(...)` returns a new `Money` value, the compiler, in most cases, constructs this value directly into the place the caller will receive it (an optimization that skips the value copy), but the conceptual model is still "a new object was constructed and returned" — the copy constructor never being called is an optimization detail, and it does not change the fact that `operator+` produces a new object.

#### Value Semantics: This Course's Context

M11/K01 showed that a struct is copied field by field on assignment; this is value semantics: when a value is assigned or passed, the two sides become independent of each other. `Money` applies this principle with C++'s own tools — the copy constructor, copy assignment, and now `operator+` returning a new value. `operator+=`, by contrast, deliberately steps outside this principle: it modifies its own object, because `+=`'s built-in meaning is already "update the value on the left" (`x += 1` also modifies `x`, it does not construct a new variable). Which of these two behavior patterns is chosen when writing an operator for a class must stay consistent with the behavior of the operator's built-in `int`/`long` counterpart — `Money` preserves this consistency: `+` produces a new value, `+=` modifies the existing one, exactly as for `int`.

#### Summary of the Copy, Temporary, and Self Distinction

This topic's seven lessons measured a single question from different angles: which object does an expression work with? Lessons 03 and 04 measured how an object acquires its own resource (constructor, destructor, RAII); lesson 05 measured how a copy separates from its original (**copy**); lesson 06 measured how a reference works with the caller's **self** without any copying; and this lesson measured when an operator produces a new **temporary**, and when it modifies its own object and returns **itself**. The four kinds — **self**, **copy**, **part**, **temporary** — correspond to the single question to ask when reading a C++ expression: which other object is the object this expression produces or operates on the same as, and which is it different from?

#### The Bounding Measurement

```cpp
// chain-measurement.cpp — how many temporaries does a + b + c produce
#include <cstdio>

#include "money.hpp"

int main() {
    Money a(10);
    Money b(20);
    Money c(30);

    Money total = a + b + c;

    use_money(total);
    return 0;
}
```

```text
cents=60
```

**CR17.** The expression `a + b + c` is evaluated left to right: first `a + b` runs and produces an unnamed `Money` with the value `cents_=30`; then this result becomes the left side of the `+ c` call. Because `operator+` is a member function, the second call's `this` must point to an object: for this reason, the result of `a + b` is constructed as **one temporary** and lives until the full expression (the end of `a + b + c;`, the semicolon) finishes, then is destroyed. The second `operator+` call's result, with the value `cents_=60`, is not constructed as a separate temporary: under C++17's guaranteed copy elision, it is constructed directly in `total`'s own storage. Two `operator+` calls therefore produce **one** temporary; `total` is the very result of the second call itself, not a copy of it. Because `Money`'s destructor does not contain a `printf` here, the moment the temporary is constructed and destroyed is not observable in this block; the count is read from the language's rule, not from this measurement. The answer to the question of "how many temporaries" a chained addition produces depends not so much on how many times the operator is called, but on where each result goes: an intermediate result that becomes the object of the next call is a temporary, while a final result that initializes a variable is that variable itself.

#### Summary

- The expression this lesson measures is of kind **temporary**: `operator+` returns a new, unnamed `Money` without modifying the operands; its return type is by value (`Money`, not a reference).
- `operator+=` modifies its own object and returns **itself** (`*this`) by reference; its return type is `Money&`.
- Binary arithmetic operators are usually written as free functions; `<<` cannot be a member function because its left side is not the class itself.
- An operator should be defined only when its built-in meaning is natural for the class.
- In a chained expression (`a + b + c`), only the intermediate result (`a + b`) is constructed as a temporary and lives until the full expression finishes; the final result is constructed directly inside `total`.
- This topic's seven lessons asked the same question: does a C++ expression work with a **self**, **copy**, **part**, or **temporary** object?

#### Next Step

This topic measured how an object acquires its own resource, is copied, is passed by reference, and produces new objects through operators. The next topic moves away from this single-object model to the **relationship** between classes — how a class extends another class's behavior, and how it is determined at run time which function gets called.

## Polymorphism and Structure

Inheritance and the base subobject, virtual functions and vtables, abstract classes, multiple inheritance and the diamond problem, exceptions, namespaces and type conversion operators — each paired with the question of which object an expression works with.

### Inheritance

Source: https://academia.sh/en/courses/cpp-fundamentals/inheritance

The measurement of whether the base subobject a derived object carries inside it stands at the same address, and is part of a single construction/destruction sequence.

The previous topic measured how an object constructs, copies, and releases its own
resource; the class stood alone, not tied to another class. This topic addresses how
one class is built on top of another: **inheritance** places one class inside another.
The lesson's measurement question is the same — which object does this expression work
with — but now the object itself has two layers: a **base subobject** and the derived
object wrapping it. This lesson asks: is the base subobject a separate object from the
derived object, or a part of it?

#### The Base Subobject and the Shared Address

`Manager` derives from `Employee`. When a `Manager` is constructed, the `Employee`
constructor runs first, then `Manager`'s own body. Naming `m` with a pointer of the
base type (`base`) — does this produce a copy, or does it carry the same address? This
needs to be measured with an address comparison.

```cpp
// inheritance_base.cpp -- derived object's base subobject and shared address
#include <iostream>
#include <string>

class Employee {
public:
    explicit Employee(std::string name) : name_(name) {
        std::cout << "Employee constructor: " << name_ << "\n";
    }
    ~Employee() {
        std::cout << "Employee destructor: " << name_ << "\n";
    }
protected:
    std::string name_;
};

class Manager : public Employee {
public:
    Manager(std::string name, int team_no) : Employee(name), team_no_(team_no) {
        std::cout << "Manager constructor: team " << team_no_ << "\n";
    }
    ~Manager() {
        std::cout << "Manager destructor\n";
    }
private:
    int team_no_;
};

int main() {
    Manager m("Aylin", 4);
    Employee* base = &m;

    std::cout << std::boolalpha;
    std::cout << "same address for m and base "
              << (static_cast<void*>(&m) == static_cast<void*>(base)) << "\n";

    return 0;
}
```

```
Employee constructor: Aylin
Manager constructor: team 4
same address for m and base true
Manager destructor
Employee destructor: Aylin
```

**PS1.** The `Manager` constructor calls the `Employee` constructor first
("Employee constructor: Aylin"), then runs its own body ("Manager constructor: team
4") — this is not two separate objects being constructed in sequence, it is **a
single object** constructed in two phases. The `base = &m` assignment does not
produce a copy, it only names the same address with a pointer of the base type: the
comparison `static_cast<void*>(&m) == static_cast<void*>(base)` confirms this,
**true**. On exit, as `m` goes out of scope, the destruction order follows
construction exactly in reverse — first `Manager`'s own destructor, then
`Employee`'s — again the two-phase teardown of a single object. (M08/K02 asked which
type resolved the call; here the question has changed — it is not the call, but the
**object** the expression points to that is measured, and while Java has no object
slicing, assigning to a base type **by value** in C++ constructs a new and incomplete
object; here there is only pointer access, no slicing.) The class is **part**: what
`base` points to is not an object independent of `m`, it is the base subobject inside
`m`.

#### Access Through a Base Reference: Reaching the Part, Not a Separate Object

Passing a `Manager` to a function with an `Employee&` parameter asks the same
question: does the reference parameter bind to an object separate from `m`, or to
the base part inside `m`?

```cpp
// inheritance_reference.cpp -- access through a base reference reaches the same part
#include <iostream>
#include <string>

class Employee {
public:
    explicit Employee(std::string name) : name_(name) {}
    std::string name() const { return name_; }
protected:
    std::string name_;
};

class Manager : public Employee {
public:
    Manager(std::string name, int team_no) : Employee(name), team_no_(team_no) {}
    int team_no() const { return team_no_; }
private:
    int team_no_;
};

bool is_same_object(const Employee& e, const Manager& m) {
    return static_cast<const void*>(&e) == static_cast<const void*>(&m);
}

void label(const Employee& e) {
    std::cout << "name seen by the reference " << e.name() << "\n";
}

int main() {
    Manager m("Baris", 7);

    label(m);

    std::cout << std::boolalpha;
    std::cout << "whether the reference parameter points to the same object as m "
              << is_same_object(m, m) << "\n";

    return 0;
}
```

```
name seen by the reference Baris
whether the reference parameter points to the same object as m true
```

**PS2.** In the call `label(m)`, `m` binds to an `Employee&`; the `name()` call reads
the `name_` field of the `Employee` part inside `m` and prints "Baris" — without ever
touching the `team_no_` that `Manager` added. In the call `is_same_object(m, m)`, the
first parameter binds `m` to `Employee&`, the second parameter binds the same `m` to
`Manager&`; comparing the addresses of the two references gives **true**. Reference
binding does not construct a copy here either — the parameter binds to the object
named in the call itself (more precisely, to that object's base part). The class is
again **part**: what the `Employee&` parameter points to is not an object living
outside `m`, it is the base subobject inside `m`.

#### The Size of an Object That Grows: A Part Enlarges the Base Object

Address equality shows the base subobject stands at the start of `m`; a size
comparison shows the base subobject occupies space **inside** `m`, in the same memory
region, not in a separate box.

```cpp
// inheritance_size.cpp -- a derived object's size encloses the base part
#include <iostream>
#include <string>

class Employee {
public:
    explicit Employee(std::string name) : name_(name) {}
protected:
    std::string name_;
};

class Manager : public Employee {
public:
    Manager(std::string name, int team_no) : Employee(name), team_no_(team_no) {}
private:
    int team_no_;
};

int main() {
    std::cout << std::boolalpha;
    std::cout << "whether Manager's size is at least Employee plus an int "
              << (sizeof(Manager) >= sizeof(Employee) + sizeof(int)) << "\n";
    std::cout << "whether Manager's size is larger than Employee's "
              << (sizeof(Manager) > sizeof(Employee)) << "\n";
    return 0;
}
```

```
whether Manager's size is at least Employee plus an int true
whether Manager's size is larger than Employee's true
```

**PS3.** `sizeof(Manager)` carries both the full size of the `Employee` subobject and
the `team_no_` field `Manager` itself adds — both comparisons are **true**. This
confirms the address equality of the first two measurements at the level of memory
layout: the base subobject does not stand inside `m` in a separate, independently
allocated box; as a physical portion of `m`, it occupies space within the same memory
block as `Manager`'s own fields. The class is **part**: the size of a `Manager`
object includes the size of the `Employee` part it carries, not as an additional
reference or pointer to it.

#### Public, Protected, and Private Inheritance: Same Address, Different External Openness

Three classes derive from the same `Base` with different access specifiers:
`PublicDerived` with `public`, `ProtectedDerived` with `protected`, `PrivateDerived`
with `private` inheritance. Can all three access `Base`'s protected member from
within themselves? And from outside, which one alone can be converted to `Base*`?

```cpp
// inheritance_access_specifiers.cpp -- public protected private inheritance carry the same address, provide different external openness
#include <iostream>

class Base {
protected:
    int value_ = 42;
};

class PublicDerived : public Base {
public:
    int read() const { return value_; }
};

class ProtectedDerived : protected Base {
public:
    int read() const { return value_; }
};

class PrivateDerived : private Base {
public:
    int read() const { return value_; }
};

int main() {
    PublicDerived pub;
    ProtectedDerived prot;
    PrivateDerived priv;

    std::cout << "read() in public inheritance " << pub.read() << "\n";
    std::cout << "read() in protected inheritance " << prot.read() << "\n";
    std::cout << "read() in private inheritance " << priv.read() << "\n";

    Base* base_pub = &pub;
    std::cout << std::boolalpha
              << "whether the externally obtained base* address matches pub in public inheritance "
              << (static_cast<void*>(base_pub) == static_cast<void*>(&pub)) << "\n";

    return 0;
}
```

```
read() in public inheritance 42
read() in protected inheritance 42
read() in private inheritance 42
whether the externally obtained base* address matches pub in public inheritance true
```

**PS19.** All three classes' `read()` function accesses `value_` from within the
class's own body, and all three print **42** — the access specifier (`public`,
`protected`, `private`) does not change access from within the class itself, because
a `protected` member is already accessible from the deriving class's own body. What
changes is visibility **from outside**: `Base* base_pub = &pub;` compiles directly
only because `PublicDerived` derives with `public` inheritance — the same conversion
from `ProtectedDerived` or `PrivateDerived` could not present the base subobject to
the outside as `Base*`. The address comparison is again **true**: the access
specifier does not change `PublicDerived`'s memory layout or the base subobject's
address, it only restricts which pointer type can reach that address from outside.
The class is **part**: the `value_` that `read()` operates on is always the class's
own base part regardless of which access specifier it was derived with — the access
specifier chooses whether to make it visible, it does not change the object.

#### A Three-Layer Constructor Chain

The first measurement showed a two-layer chain (`Employee` → `Manager`). When the
chain extends to a third layer (`A` → `B` → `C`), how does the construction and
destruction order expand?

```cpp
// inheritance_three_layer_chain.cpp -- three-layer constructor chain from the most base to the most derived
#include <iostream>

class A {
public:
    A() { std::cout << "A constructor\n"; }
    ~A() { std::cout << "A destructor\n"; }
};

class B : public A {
public:
    B() { std::cout << "B constructor\n"; }
    ~B() { std::cout << "B destructor\n"; }
};

class C : public B {
public:
    C() { std::cout << "C constructor\n"; }
    ~C() { std::cout << "C destructor\n"; }
};

int main() {
    std::cout << "-- construction --\n";
    {
        C c;
        std::cout << "-- end of scope, destruction begins --\n";
    }
    return 0;
}
```

```
-- construction --
A constructor
B constructor
C constructor
-- end of scope, destruction begins --
C destructor
B destructor
A destructor
```

**PS20.** `C c;` constructs a single object, but this construction splits into three
phases: first the most base `A`, then `B`, then `C`'s own body — no matter how many
layers the chain has, the order is always **most base to most derived**. Destruction
runs in exactly the reverse order at end of scope: first `C`, then `B`, then `A`.
This is a generalization of the two-phase construction/destruction from the first
measurement — a `C` object actually consists of three nested parts (the `A`
subobject, the `B` subobject growing inside it, and `C`'s own fields growing inside
that), and each part is constructed only after the part before it completes. The
class is **part**: `C` is a single object, but that object has three layers, and
each layer is built on top of the previous one.

#### Assigning by Value to the Base Slices the Object: A Separate Copy

Previous measurements always accessed the base part through a pointer or a
reference — the address was always the same. When a `Manager` object is assigned
**by value** to a variable of type `Employee`, does the address stay the same, or
does an independent object emerge?

```cpp
// inheritance_slicing.cpp -- assigning by value to the base slices the object, producing a separate independent copy
#include <iostream>
#include <string>

class Employee {
public:
    explicit Employee(std::string name) : name_(std::move(name)) {}
    std::string name() const { return name_; }
    void set_name(std::string name) { name_ = std::move(name); }
protected:
    std::string name_;
};

class Manager : public Employee {
public:
    Manager(std::string name, int team_no) : Employee(std::move(name)), team_no_(team_no) {}
    int team_no() const { return team_no_; }
private:
    int team_no_;
};

int main() {
    Manager m("Deniz", 9);
    Employee sliced = m;

    std::cout << std::boolalpha;
    std::cout << "whether sliced and m carry the same address "
              << (static_cast<void*>(&sliced) == static_cast<const void*>(&m)) << "\n";

    sliced.set_name("Other");
    std::cout << "m's name after sliced's name is changed " << m.name() << "\n";
    std::cout << "sliced object's name " << sliced.name() << "\n";

    return 0;
}
```

```
whether sliced and m carry the same address false
m's name after sliced's name is changed Deniz
sliced object's name Other
```

**PS21.** `Employee sliced = m;` does not construct a pointer or a reference, it
constructs a **new `Employee` object** — `Employee`'s copy constructor copies
`name_` from `m`'s base part, and `Manager`'s added `team_no_` is not carried at
all, because `Employee`'s own definition has no such field. The address comparison
confirms this: **false** — `sliced` is a separate object living at its own address,
independent of `m`. When `sliced`'s name is changed, `m`'s name stays **Deniz**: the
two objects are independent of each other. This is a **different class** from the
rest of the lesson: while pointer and reference access always reach the same base
**part**, assignment by value (slicing) produces a new, independent **copy** of type
`Employee` — and this copy does not carry the fields `Manager` added, only the part
`Employee` defines.

#### Overload Selection by Static Type, Object Identity Does Not Change

The `info` function is overloaded for both `Employee&` and `Manager&`. When the same
`m` object is passed to `info` once as `Manager&` and once through an `Employee&`
reference, which overload is selected — and do both work with the same object?

```cpp
// inheritance_overload_comparison.cpp -- overload selection by static type, object identity fixed at run time
#include <iostream>
#include <string>

class Employee {
public:
    explicit Employee(std::string name) : name_(std::move(name)) {}
    std::string name_;
};

class Manager : public Employee {
public:
    Manager(std::string name, int team_no) : Employee(std::move(name)), team_no_(team_no) {}
    int team_no_;
};

void info(const Employee& e) {
    std::cout << "info(Employee&) called, name " << e.name_ << "\n";
}

void info(const Manager& m) {
    std::cout << "info(Manager&) called, name " << m.name_ << ", team " << m.team_no_ << "\n";
}

int main() {
    Manager m("Kaan", 3);
    Employee& base_ref = m;

    info(m);
    info(base_ref);

    std::cout << std::boolalpha
              << "whether both calls work with the same m object "
              << (static_cast<const void*>(&m) == static_cast<const void*>(&base_ref)) << "\n";

    return 0;
}
```

```
info(Manager&) called, name Kaan, team 3
info(Employee&) called, name Kaan
whether both calls work with the same m object true
```

**PS22.** `info(m)` selects `info(Manager&)` by looking at `m`'s static type
(`Manager`) at compile time; `info(base_ref)` selects `info(Employee&)` by looking
at `base_ref`'s static type (`Employee&`) — neither is `virtual`, the selection is
made entirely **at compile time**, based on the expression's static type. This is on
the same axis as the question measured in M08/K02: which overload is selected is a
**compile-time** decision. But this lesson measures a different question: which
**object** does the selected function work with? The address comparison is **true**
— the object `info(Manager&)` works with as `m` and the object `info(Employee&)`
works with as `base_ref` point to exactly the same object. Overload selection
determines which **function** is called based on the static type; object identity
stays the same regardless of this selection. The class is **part**: two different
overloads work on the same object's base part.

#### The Bounding Measurement

The inheritance measured in this lesson is **single** and **non-virtual**: `Manager`
derives from a single base class, and no function was `virtual`, so the observation
that the base subobject stands at the start of `m` and its address coincides with
`m`'s is bound to these conditions — under multiple inheritance (the Multiple
Inheritance and the Diamond Problem lesson), the second and later base subobjects
may stand at a different offset, and their addresses may not coincide with `m`'s.
The measurement also does not cover the case where `Employee` exists on its own,
without a `Manager` — it measured only the `Employee` part inside a `Manager`
object. Which function a call through a base pointer or reference runs — whether the
call looks at the static type or the real type — is not this lesson's subject; the
next lesson measures that.

#### Summary

- When a `Manager` object is constructed, the `Employee` constructor runs first,
  then `Manager`'s own body — not the construction of two separate objects, but two
  phases of a single object.
- `Employee* base = &m` does not produce a copy; `base` and `m` carry the same
  address, because under single, non-virtual inheritance the base subobject stands
  at the start of the derived object.
- Passing `m` to an `Employee&` parameter also binds to the same address — reference
  binding does not construct a copy, the class is **part**.
- `sizeof(Manager)` carries both the full size of the `Employee` subobject and the
  fields `Manager` itself adds; the base subobject does not stand in a separate box,
  it stands in a physical portion of the same object.
- Destruction order follows construction in reverse: first `Manager`'s own
  destructor, then `Employee`'s — again the two-phase teardown of a single object.

#### Next Step

In this lesson the base subobject's address always coincided with `m`'s, because no
function was `virtual` and the function to be called was determined at compile
time, by looking at the expression's **static type**. The next lesson, Virtual
Functions and Vtables, measures how a call through a base pointer or reference
determines which function runs based on the object's **real** type — and this time
what is measured is not address equality, but that the same expression always works
with the same object at run time.

### Virtual Functions and Vtables

Source: https://academia.sh/en/courses/cpp-fundamentals/virtual-functions-and-vtables

The measurement of whether a virtual call through a base pointer or reference always works with the same object, independent of the expression's static type.

The previous lesson measured that the base subobject is a **part** of the derived
object, its address coinciding with it — but no function was `virtual`, and the
function to be called was determined at compile time by looking at the expression's
static type. This lesson adds the `virtual` keyword: now a call through a `Shape*`
or `Shape&` decides which function to run not by the pointer's static type, but by
the **real type of the object it points to**. The question has changed: it is not
the base subobject's address, but **which object** a virtual call really works with
that is measured.

#### A Virtual Call Reaches the Same Object

`Rectangle` redefines `Shape`'s `introduce` function. When object `r` is accessed
both through a `Shape*` pointer and a `Shape&` reference and `introduce` is called,
does both reach `r`'s own function?

```cpp
// virtual_same_object.cpp -- virtual call reaches the same object independent of static type
#include <iostream>

class Shape {
public:
    virtual ~Shape() = default;
    virtual void introduce(const void* expected) const {
        std::cout << "introduce(Shape): running object same as expected "
                  << std::boolalpha << (static_cast<const void*>(this) == expected) << "\n";
    }
};

class Rectangle : public Shape {
public:
    void introduce(const void* expected) const override {
        std::cout << "introduce(Rectangle): running object same as expected "
                  << std::boolalpha << (static_cast<const void*>(this) == expected) << "\n";
    }
};

int main() {
    Rectangle r;
    Shape* base_ptr = &r;
    Shape& base_ref = r;

    base_ptr->introduce(&r);
    base_ref.introduce(&r);

    return 0;
}
```

```
introduce(Rectangle): running object same as expected true
introduce(Rectangle): running object same as expected true
```

**PS4.** Both calls were made through an expression whose static type is `Shape`
(`base_ptr`, `base_ref`), but both printed "introduce(Rectangle)" — the virtual
call selected `Rectangle::introduce` by looking not at the pointer's/reference's
static type, but at the real type of the object it points to. Inside the function,
comparing `this` to `r`'s address returns **true**: the call not only selects the
right function, it also runs that selected function exactly on `r` itself, not on a
copy or another object. (M08/K02 asked which type resolved the call; a similar
mechanism exists here too, but what is measured is which **object** the call works
with — and while Java has no object slicing, assigning to a base type by value in
C++ would construct a new and incomplete object; here there is only pointer/
reference access, slicing does not come into play.) The manually built method
table (a struct carrying function pointers) in M11/K03's Object-Like Design lesson
corresponds here to the compiler-generated virtual function table; the mechanism's
details were covered there and are not re-explained here. The class is **self**:
`this` always carries `r`'s address, independent of the static type of the
expression through which the call was made.

#### An Array of Base Pointers: Each Call Reaches Its Own Object

When a `Shape*` array points to different derived objects, does each element reach
the object it itself points to, or is there mixing between them?

```cpp
// virtual_array.cpp -- each base pointer in the array reaches the object it itself points to
#include <iostream>

class Shape {
public:
    virtual ~Shape() = default;
    virtual bool same_as(const void* address) const {
        return static_cast<const void*>(this) == address;
    }
};

class Rectangle : public Shape {};
class Triangle : public Shape {};

int main() {
    Rectangle r;
    Triangle t;
    Shape* shapes[2] = { &r, &t };

    std::cout << std::boolalpha;
    std::cout << "shapes[0] same as its own object r "
              << shapes[0]->same_as(&r) << "\n";
    std::cout << "shapes[1] same as its own object t "
              << shapes[1]->same_as(&t) << "\n";
    std::cout << "shapes[0] same as t (cross-check) "
              << shapes[0]->same_as(&t) << "\n";

    return 0;
}
```

```
shapes[0] same as its own object r true
shapes[1] same as its own object t true
shapes[0] same as t (cross-check) false
```

**PS5.** `Rectangle` and `Triangle` do not redefine `introduce`, they inherit
`Shape::same_as` as is — but the function still binds `this` to the real object of
the element it was called through, every time it is called. `shapes[0]->same_as(&r)`
is **true**, `shapes[1]->same_as(&t)` is **true**: each element reaches its own
object. The cross-check makes this even clearer — `shapes[0]` (the element pointing
to `r`) compared against `&t` returns **false**, because the object `shapes[0]`
works with is `r`, not `t`. The class is **self**: every base pointer in the array,
even though it carries the same base type, works with no object other than the
particular object it itself points to.

#### Passing to a Function by Reference Does Not Change the Object

An object passed to a function with a `const Shape&` parameter — inside the
function, is it still the same object as outside, or the function's own copy?

```cpp
// virtual_reference_parameter.cpp -- object passed by reference to a function is the same as the one outside
#include <iostream>

class Shape {
public:
    virtual ~Shape() = default;
    virtual bool same_as(const void* address) const {
        return static_cast<const void*>(this) == address;
    }
};

class Rectangle : public Shape {};

void verify(const Shape& s, const void* expected) {
    std::cout << std::boolalpha
              << "object called inside the function same as expected "
              << s.same_as(expected) << "\n";
}

int main() {
    Rectangle r;
    verify(r, &r);
    return 0;
}
```

```
object called inside the function same as expected true
```

**PS6.** In the call `verify(r, &r)`, `s` is not a copy of `r`, it is a reference
that binds to `r` itself — the `const Shape&` parameter type provides this without
constructing a copy. When `s.same_as(&r)` is called inside the function, the virtual
call again selects `Shape::same_as` (because `Rectangle` did not redefine it), and
comparing `this` to the outside `r`'s address returns **true**. Crossing the
function boundary — as long as the parameter is a reference — does not change the
object's identity: `s` inside `verify` is the same object as `r` inside `main`. The
class is **self**: as long as the function call does not construct a copy, a
virtual call always works with the real object at the point the call started.

#### override and final: Still Reaching the Same Object by Real Type

`BorderedTriangle` derives from `Triangle`, marks `same_as` as both `override` and
`final`, and is itself `final`. These two keywords affect compile-time checking, not
run-time behavior — but does the virtual call that ends up running still reach the
same object?

```cpp
// virtual_override_final.cpp -- virtual call marked override and final still runs based on the object's real type
#include <iostream>

class Shape {
public:
    virtual ~Shape() = default;
    virtual bool same_as(const void* address) const {
        return static_cast<const void*>(this) == address;
    }
};

class Triangle : public Shape {
public:
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
};

class BorderedTriangle final : public Triangle {
public:
    bool same_as(const void* address) const override final {
        return static_cast<const void*>(this) == address;
    }
};

int main() {
    BorderedTriangle b;
    Shape& base_ref = b;

    std::cout << std::boolalpha
              << "same_as called through the base reference same as expected "
              << base_ref.same_as(&b) << "\n";

    return 0;
}
```

```
same_as called through the base reference same as expected true
```

**PS23.** `override` tells the compiler "this function redefines a base class
function," and if the signature does not match (for example if `const` is
forgotten, or a parameter type is written wrong) it produces a compile error — this
prevents a mismatched signature from silently defining a new, separate function (and
the base function never being redefined). This protection operates at compile time;
since the sandbox only runs code that compiles successfully, how a signature
mismatch leads to an error cannot be shown by running it here, only narrated.
`final` prevents both class `BorderedTriangle` and function `same_as` from being
further derived from/redefined, at compile time — this too is something observable
not by running it, but only by a forbidden violation failing to compile. The part
that runs has not changed: `base_ref.same_as(&b)` prints **true**, because
`override`/`final` do not change run-time behavior, they only narrow which
signatures are considered valid. The class is **self**: a `final` class's object,
like any other, is exactly the object the virtual call reaches.

#### Virtual Destructor: Deleting Through a Base Pointer Runs the Correct Chain

`Shape`'s destructor is `virtual`. When a `Rectangle` constructed with `new` is
`delete`d through a `Shape*`, does destruction start from `Rectangle`'s own
destructor, or jump straight to `Shape`'s?

```cpp
// virtual_destructor_delete_through_base_pointer.cpp -- virtual destructor runs the correct destruction chain when deleted through a base pointer
#include <iostream>

class Shape {
public:
    virtual ~Shape() { std::cout << "Shape destructor\n"; }
};

class Rectangle : public Shape {
public:
    ~Rectangle() override { std::cout << "Rectangle destructor\n"; }
};

int main() {
    Shape* base_ptr = new Rectangle();
    std::cout << "-- deletion begins --\n";
    delete base_ptr;
    return 0;
}
```

```
-- deletion begins --
Rectangle destructor
Shape destructor
```

**PS24.** `base_ptr`'s static type is `Shape*`, but when `delete base_ptr` is
called, **Rectangle destructor** is printed first, then **Shape destructor** —
destruction, like construction, runs from most derived to most base, and what lets
it start in the correct order is `~Shape()` being `virtual`. This is the behavior
the standard defines: when the base class's destructor is virtual, a `delete`
through a base pointer starts by calling the real (dynamic) type's destructor. The
counterpart has no defined outcome: if `~Shape()` were not `virtual`, this
`delete base_ptr`, where the static and dynamic types differ, would be **undefined
behavior** per the standard. On common compilers this usually shows up as only
`Shape`'s destructor running and the resources `Rectangle` added not being
released, but that is a compiler behavior, not a language guarantee. This branch is
not run here: since undefined behavior does not give a deterministic output, it has
no result verifiable in the sandbox, it can only be narrated. The class is **self**:
the `delete` call always runs the full destruction chain of `r` (the real object),
independent of `base_ptr`'s static type.

#### A Manually Built Method Table and the Compiler's Virtual Function Table Give the Same Result

M11/K03's Object-Like Design lesson manually built a "method table" using a
`struct` that carried function pointers. Does a call through such a manually built
table and a `virtual` call through the compiler-generated virtual function table
give the same result for the same object?

```cpp
// virtual_manual_method_table.cpp -- a manually built method table gives the same result as the compiler-generated virtual function table
#include <iostream>

struct Shape {
    virtual ~Shape() = default;
    virtual int area() const { return 0; }
};

struct Square : public Shape {
    explicit Square(int side) : side_(side) {}
    int area() const override { return side_ * side_; }
    int side_;
};

struct ManualMethodTable {
    int (*area)(const void*);
};

int square_area_manual(const void* object) {
    return static_cast<const Square*>(object)->area();
}

int main() {
    Square square(5);
    Shape& virtual_access = square;

    ManualMethodTable table{ square_area_manual };

    std::cout << "compiler's virtual call: " << virtual_access.area() << "\n";
    std::cout << "manually built table call: " << table.area(&square) << "\n";
    std::cout << std::boolalpha << "both results the same "
              << (virtual_access.area() == table.area(&square)) << "\n";

    return 0;
}
```

```
compiler's virtual call: 25
manually built table call: 25
both results the same true
```

**PS25.** `virtual_access.area()` reaches `Square::area` through the
compiler-generated virtual function table; `table.area(&square)` reaches the same
function (this time directly through a function pointer) through the manually built
`ManualMethodTable`. Both print **25** and the comparison is **true**: two different
mechanisms select the same function for the same object. The difference is in how
the selection is made — in a virtual call the compiler adds a hidden virtual
function table pointer to every object, and `area()` finds the right entry through
that pointer every time it is called; in a manually built table this step is the
responsibility of the programmer here in the `ManualMethodTable table{...}` line and
matching the table to the correct object. This mechanism was covered in detail in
M11/K03; here only the fact that the two approaches arrive at the same result is
verified. The class is **self**: both calls work on `square` itself.

#### The Structural Cost of Virtual Dynamic Dispatch: A Larger Object

`VirtualPoint` carries the same two `int` fields as `NonVirtualPoint`, with one
difference: it has a virtual destructor. Are these two classes, carrying the same
fields, the same size, or does carrying a virtual function have a per-object
structural cost?

```cpp
// virtual_dynamic_dispatch_cost.cpp -- a class carrying a virtual function is larger than a non-virtual class carrying the same fields
#include <iostream>

class NonVirtualPoint {
public:
    int x_ = 0;
    int y_ = 0;
};

class VirtualPoint {
public:
    virtual ~VirtualPoint() = default;
    int x_ = 0;
    int y_ = 0;
};

int main() {
    std::cout << std::boolalpha
              << "is the class carrying a virtual function larger than the one that does not "
              << (sizeof(VirtualPoint) > sizeof(NonVirtualPoint)) << "\n";
    return 0;
}
```

```
is the class carrying a virtual function larger than the one that does not true
```

**PS26.** The two classes carry exactly the same two `int` fields, but the
comparison is **true**: `VirtualPoint` is larger. The difference comes from the
hidden virtual function table pointer the compiler adds to every object as soon as
a `virtual` function is defined — this is dynamic dispatch's **per-object,
one-time** structural cost. Besides this there is also a **per-call** cost: every
virtual call performs an indirection that first finds the right entry through the
object's virtual function table pointer, instead of a direct jump. This second cost
is not measured here, because a timing measurement would depend on hardware,
compiler optimization level, and the sandbox's own load — this lesson does not
report such environment-dependent data. What is measurable and deterministic is
only the size difference. The class is **part**: the virtual function table
pointer is a part of the object, not a separate object.

#### Virtual Call Inside the Constructor: Goes to the Base, Not the Derived

`Base`'s constructor calls `define()` inside its own body; `Derived` redefines this
function. When a `Derived` object is constructed, does this call inside `Base`'s
constructor reach `Derived::define`, or `Base::define`?

```cpp
// virtual_call_inside_constructor.cpp -- virtual call inside a constructor goes to the base's own function, not the derived's
#include <iostream>

class Base {
public:
    Base() {
        std::cout << "calling define() inside Base constructor\n";
        define();
    }
    virtual void define() const {
        std::cout << "Base::define ran\n";
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "calling define() inside Derived constructor\n";
        define();
    }
    void define() const override {
        std::cout << "Derived::define ran\n";
    }
};

int main() {
    Derived d;
    return 0;
}
```

```
calling define() inside Base constructor
Base::define ran
calling define() inside Derived constructor
Derived::define ran
```

**PS27.** `d`'s final form is a `Derived`, but while `Base`'s constructor is
running, the `define()` call inside it runs **Base::define**, not
`Derived::define`. Why: while `Base`'s constructor is running, `Derived`'s own part
has not been constructed yet — the object's effective type at that moment, from the
perspective of virtual dispatch, is still `Base`. This changes as the chain
proceeds upward: while `Derived`'s own constructor is running, the `define()` call
made inside it now runs **Derived::define**, because at that point the object's
`Derived` part has also been constructed. The class is **self**: both calls work on
`d` itself, but which function is selected depends on where the construction chain
stands at the moment the call is made.

#### The Bounding Measurement

The virtual calls measured in this lesson were always made through a pointer or a
reference; assigning `Rectangle` to a `Shape` variable **by value**
(`Shape s = r;`) is outside this measurement's scope — such an assignment does not
engage the virtual call, it engages the slicing touched on at the end of the
previous lesson, and the result is a new, incomplete `Shape` object. The
measurement also covers only the simple cases where `introduce` and `same_as` do
not themselves make another virtual call inside them; the incomplete destruction
that could arise if a base destructor were not virtual was never observed in this
lesson, because both classes (`Shape` and its derivatives) carry a virtual
destructor. A base class built entirely from functions with no body at all, only
presenting an interface — abstract classes — is not this lesson's subject; the
next lesson measures that.

#### Summary

- A virtual call through a `Shape*` or `Shape&` decides which function to run not
  by the expression's static type, but by the real type of the object it points to.
- Inside the selected function, `this` always carries the address of the same real
  object, independent of the base-type expression the call was made through — the
  class is **self**.
- Each element in a `Shape*` array reaches the particular object it itself points
  to; a cross-check confirms it does not match another element's object.
- An object passed to a function with a `const Shape&` parameter is the same
  object outside as it is inside the function — reference binding does not
  construct a copy.
- Assigning **by value** to the base type (slicing) is outside this lesson's
  scope; a virtual call works this way only under pointer/reference access.

#### Next Step

In this lesson `Shape::introduce` and `Shape::same_as` had a body — they could be
called even though derived classes did not redefine them. The next lesson, Abstract
Classes and Interfaces, measures the case where a base class is built entirely from
functions with no body at all, declaring only a contract — there, an object cannot
be constructed directly from the base class, only from derived classes; what is
measured is again which object a virtual call works with, but this time the base
type has no instance of its own at all.

### Abstract Classes and Interfaces

Source: https://academia.sh/en/courses/cpp-fundamentals/abstract-classes-and-interfaces

The measurement of how a pure virtual function guarantees that no instance can be constructed from the base class, and that an interface is a pure contract carrying no data.

The previous lesson showed that `Shape::introduce` had a body, and could be called
even though derived classes did not redefine it. This lesson covers the case where
a base class is built entirely from functions with no body at all, declaring only a
contract: a **pure virtual function** (marked with `= 0`). No object can be
constructed directly from a class carrying such a function — only from derived
classes that fill it in **completely**. The measurement question is the same: which
object does a call through a base pointer or reference work with — but this time
the base type has no instance of its own at all.

#### No Object Can Be Constructed from the Base Class, Only from Derived Ones

`Vehicle`'s `same_as` function is pure virtual (`= 0`); this turns constructing an
object directly from `Vehicle` into a compile error — `Vehicle v;` cannot be
written. Only classes like `Car` and `Bicycle` that fill in `same_as` can have
objects constructed. Does each element in a `Vehicle*` array still reach the
particular object it itself points to?

```cpp
// abstract_base.cpp -- no instance of a class carrying a pure virtual function can be constructed, only of those that fill it in
#include <iostream>

class Vehicle {
public:
    virtual ~Vehicle() = default;
    virtual bool same_as(const void* address) const = 0;
};

class Car : public Vehicle {
public:
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
};

class Bicycle : public Vehicle {
public:
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
};

int main() {
    Car c;
    Bicycle b;
    Vehicle* vehicles[2] = { &c, &b };

    std::cout << std::boolalpha;
    std::cout << "vehicles[0] same as its own object c "
              << vehicles[0]->same_as(&c) << "\n";
    std::cout << "vehicles[1] same as its own object b "
              << vehicles[1]->same_as(&b) << "\n";
    std::cout << "vehicles[0] same as b (cross-check) "
              << vehicles[0]->same_as(&b) << "\n";

    return 0;
}
```

```
vehicles[0] same as its own object c true
vehicles[1] same as its own object b true
vehicles[0] same as b (cross-check) false
```

**PS7.** If `Vehicle v;` were written, the compiler would reject it — the pure
virtual `same_as` leaves `Vehicle` incomplete on its own, only classes like `Car`
and `Bicycle` that completely fill in the function can be constructed. This means
the only thing a `Vehicle*` can point to is the instance of a concrete class that
fills in `same_as` — there is no possibility at all of falling back to an
instance of the base class itself, a "spare" instance. `vehicles[0]->same_as(&c)`
is **true**, `vehicles[1]->same_as(&b)` is **true**, the cross-check is **false**:
each element reaches its own concrete object. (M08/K02 asked which type resolved
the call; here, since the base type has no instance of its own at all, resolution
always falls to a concrete type — and just as an interface reference in Java can
never point to an object of the pure interface type itself, a pure virtual function
in C++ provides the same restriction.) The class is **self**: the call necessarily
works with a concrete derived object, because the base type itself can never exist.

#### An Inherited Body Also Works with the Same Object

Alongside the pure virtual `same_as`, `Vehicle` also carries a `maintenance_info`
with a body. `Car` does not redefine it, `Bicycle` does. When the inherited body
runs, does `this` still carry the address of the called object?

```cpp
// abstract_inherited_function.cpp -- an inherited function with a body also carries the address of the called object
#include <iostream>

class Vehicle {
public:
    virtual ~Vehicle() = default;
    virtual bool same_as(const void* address) const = 0;
    virtual void maintenance_info(const void* expected) const {
        std::cout << "Vehicle::maintenance_info running object same as expected "
                  << std::boolalpha << (static_cast<const void*>(this) == expected) << "\n";
    }
};

class Car : public Vehicle {
public:
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
};

class Bicycle : public Vehicle {
public:
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
    void maintenance_info(const void* expected) const override {
        std::cout << "Bicycle::maintenance_info running object same as expected "
                  << std::boolalpha << (static_cast<const void*>(this) == expected) << "\n";
    }
};

int main() {
    Car c;
    Bicycle b;
    Vehicle* v1 = &c;
    Vehicle* v2 = &b;

    v1->maintenance_info(&c);
    v2->maintenance_info(&b);

    return 0;
}
```

```
Vehicle::maintenance_info running object same as expected true
Bicycle::maintenance_info running object same as expected true
```

**PS8.** Since `Car` does not redefine `maintenance_info`, the call
`v1->maintenance_info(&c)` runs the body of `Vehicle::maintenance_info` — but even
inside this body, `this` compared against `c`'s address returns **true**. Since
`Bicycle` supplies its own body, `v2->maintenance_info(&b)` runs
`Bicycle::maintenance_info`, and `this` is again `b`'s address. An inherited body
running does not mean `Vehicle` has an instance of its own — that body is only ever
run on a concrete `Car` object. The class is **self**: even the common body
supplied by the base class works with no object other than the concrete object it
was called on.

#### An Interface: Only a Contract, No Shared Data

`Vehicle` carried no data, but it did carry a common body — it was a full abstract
class. `Printable` is different: it has no data field, no function with a body at
all, only a contract. `Report` fills in this contract and carries its own data.

```cpp
// interface_contract.cpp -- an interface carries no data at all, the one filling in the contract carries its own data
#include <iostream>
#include <string>
#include <utility>

class Printable {
public:
    virtual ~Printable() = default;
    virtual bool same_as(const void* address) const = 0;
};

class Report : public Printable {
public:
    explicit Report(std::string title) : title_(std::move(title)) {}
    bool same_as(const void* address) const override {
        return static_cast<const void*>(this) == address;
    }
    const std::string& title() const { return title_; }
private:
    std::string title_;
};

void list_item(const Printable& p, const void* expected) {
    std::cout << std::boolalpha
              << "object called inside list_item same as expected "
              << p.same_as(expected) << "\n";
}

int main() {
    Report r("Annual Report");
    std::cout << "the report's title " << r.title() << "\n";
    list_item(r, &r);
    return 0;
}
```

```
the report's title Annual Report
object called inside list_item same as expected true
```

**PS9.** `Printable` declares no data field at all; `title_` belongs entirely to
`Report` — `Printable` never touches this data, it only imposes the `same_as`
contract. When `r` is bound to a `Printable&` and passed into `list_item`,
`p.same_as(&r)` is again **true**: reference binding does not construct a copy here
either, `p` is the same object as `r` inside `main`. The difference between
`Vehicle` and `Printable` is concrete: `Vehicle` can carry data and offer functions
with a common body (abstract class), `Printable` is purely signatures, no data, no
body at all (interface). The class is **self**: in both cases, the call always
works with the concrete object that fills in the contract.

#### A Pure Virtual Function Can Have a Body, But Only Through a Qualified Call

`= 0` makes a function pure virtual and prevents the carrying class from being
instantiated — but this does not mean the function can never have a body.
`NoisyVehicle::warn` is both pure virtual and has a body. Is this body reached
through an ordinary virtual call, or some other way?

```cpp
// abstract_pure_virtual_body.cpp -- a pure virtual function can have a body, but it only runs through a qualified call
#include <iostream>

class NoisyVehicle {
public:
    virtual ~NoisyVehicle() = default;
    virtual void warn() const = 0;
};

void NoisyVehicle::warn() const {
    std::cout << "NoisyVehicle::warn (default body) ran\n";
}

class Truck : public NoisyVehicle {
public:
    void warn() const override {
        std::cout << "Truck::warn ran, now calling the base body through a qualified call\n";
        NoisyVehicle::warn();
    }
};

int main() {
    Truck t;
    NoisyVehicle& base_ref = t;
    base_ref.warn();
    return 0;
}
```

```
Truck::warn ran, now calling the base body through a qualified call
NoisyVehicle::warn (default body) ran
```

**PS28.** `base_ref.warn()` is an ordinary virtual call — and since `Truck`
redefines `warn`, it never reaches `NoisyVehicle`'s body on its own, just like every
`override` in the previous lessons. `NoisyVehicle::warn`'s body only runs when
manually called with a **qualified** call (`NoisyVehicle::warn();`) from inside
`Truck::warn` — this line bypasses virtual dispatch and targets that name directly.
"Pure virtual" and "bodiless" diverge here: `= 0` is what prevents the class from
being instantiated and forces derived classes to fill in the function; whether it
has a body is a separate question, and if it does, that body is reachable only
through a qualified call, not ordinary virtual dispatch. The class is **self**:
even the qualified call works on `t` itself, only name resolution determines which
body runs.

#### No Instance of an Abstract Base Can Be Constructed, But a Concrete Base Can Be Taken by Value and Sliced

Because `Vehicle` carries a pure virtual function, `Vehicle v;` never compiles at
all — this means a **value** of type `Vehicle` can also never exist, so the risk of
object slicing cannot even arise for `Vehicle`. How does the situation change when
a base class is not abstract, and has a full body?

```cpp
// abstract_concrete_base_by_value.cpp -- no instance of an abstract base can be constructed, but a concrete base can be taken by value and sliced
#include <iostream>
#include <string>

class VehicleRecord {
public:
    explicit VehicleRecord(std::string plate) : plate_(std::move(plate)) {}
    std::string plate() const { return plate_; }
protected:
    std::string plate_;
};

class DetailedRecord : public VehicleRecord {
public:
    DetailedRecord(std::string plate, int km)
        : VehicleRecord(std::move(plate)), km_(km) {}
    int km() const { return km_; }
private:
    int km_;
};

int main() {
    DetailedRecord detailed("34ABC123", 15000);
    VehicleRecord sliced = detailed;

    std::cout << std::boolalpha;
    std::cout << "sliced and detailed carry the same address "
              << (static_cast<void*>(&sliced) == static_cast<const void*>(&detailed)) << "\n";
    std::cout << "sliced object's plate " << sliced.plate() << "\n";

    return 0;
}
```

```
sliced and detailed carry the same address false
sliced object's plate 34ABC123
```

**PS29.** `VehicleRecord` carries no pure virtual function, it is a concrete class
— so `VehicleRecord sliced = detailed;` compiles and produces the same slicing
measured in PS21 in the Inheritance lesson: `sliced` is a separate object living at
its own address, independent of `detailed` (**false**), and the `km_` field
`DetailedRecord` added is not carried over at all. `Vehicle` has no counterpart to
this line, because defining a variable of type `Vehicle` is itself a compile error
— no `Vehicle` value that could be the target of slicing can ever exist.
Abstractness means not only "the obligation to redefine," but also "a value of the
base type can never come into existence": an abstract base can be accessed by
pointer or reference, but can never be placed by value into a variable, parameter,
or return value — this also makes it structurally immune to slicing. The slicing
risk exists only for concrete classes. The class is **copy**: `sliced` is an
independent copy of `detailed`'s base part.

#### The Role of an Interface: Handling Unrelated Types Under One Contract

`Report` and `Invoice` do not derive from each other, they share no data or
behavior at all — their only common point is filling in the `Printable` contract.
Can these two be processed uniformly, in the same vector, without their concrete
types being known?

```cpp
// interface_role_multiple_types.cpp -- different concrete types can be processed uniformly through the same interface
#include <iostream>
#include <string>
#include <vector>

class Printable {
public:
    virtual ~Printable() = default;
    virtual std::string text() const = 0;
};

class Report : public Printable {
public:
    explicit Report(std::string title) : title_(std::move(title)) {}
    std::string text() const override { return "Report: " + title_; }
private:
    std::string title_;
};

class Invoice : public Printable {
public:
    explicit Invoice(int amount) : amount_(amount) {}
    std::string text() const override { return "Invoice: " + std::to_string(amount_); }
private:
    int amount_;
};

int main() {
    Report r("Annual Report");
    Invoice i(150);
    std::vector<Printable*> documents{ &r, &i };

    for (const auto* doc : documents) {
        std::cout << doc->text() << "\n";
    }

    return 0;
}
```

```
Report: Annual Report
Invoice: 150
```

**PS30.** `Report` and `Invoice` are not related in the same hierarchy tree, they
share no data field or function with a body — their only bond is that both fill in
`Printable`. The `documents` vector holds both under a single `Printable*` type,
and the loop calls `text()` without ever knowing the element's concrete type; each
call still reaches the correct concrete type's function: "Report: Annual Report"
and "Invoice: 150". This shows the real role of an interface: unlike an abstract
class, an interface does not establish kinship, it only imposes a contract by
signature — every type that fills in the contract can be processed in the same
collection, the same loop, even with no other commonality between them. The class
is **self**: every `text()` call works with the very concrete object the element in
the loop points to.

#### An Interface Also Needs a Virtual Destructor

Although `Printable` appears to offer only a contract, being able to `delete` a
concrete derived object like `Report` through a `Printable*` still requires its own
destructor to be virtual. Does this lesson confirm that?

```cpp
// interface_virtual_destructor.cpp -- an interface's virtual destructor runs the full destruction chain of the derived object
#include <iostream>

class Printable {
public:
    virtual ~Printable() { std::cout << "Printable destructor\n"; }
    virtual void print() const = 0;
};

class Report : public Printable {
public:
    ~Report() override { std::cout << "Report destructor\n"; }
    void print() const override { std::cout << "Report::print\n"; }
};

int main() {
    Printable* doc = new Report();
    doc->print();
    std::cout << "-- deletion begins --\n";
    delete doc;
    return 0;
}
```

```
Report::print
-- deletion begins --
Report destructor
Printable destructor
```

**PS31.** `doc`'s static type is `Printable*`, but `delete doc` runs **Report
destructor** first, then **Printable destructor** — the same principle measured as
PS24 in the Virtual Functions and Vtables lesson, here in the interface context.
Even though `Printable` is a contract offering only pure virtual functions, if its
destructor were not `virtual`, that same `delete doc` would call only
`Printable`'s own destructor, `Report`'s resources never being released — and with
the static and dynamic types differing, deleting through a non-virtual destructor
would be undefined behavior. This branch, as in PS24, is not run here because it
would not give a deterministic output. Conclusion: "offering only a contract" does
not exempt a class from the virtual-destructor requirement — if polymorphic
deletion through a base pointer is going to happen, the destructor must be virtual,
interface included. The class is **self**: the destruction chain always operates on
the real `Report` object `doc` points to.

#### The Bounding Measurement

The abstractness measured in this lesson is under **single inheritance**: each
concrete class filled in exactly one abstract base class or interface. The case
where a class derives from multiple base classes at once, filling in multiple
contracts simultaneously — multiple inheritance — is outside this lesson's scope;
the next lesson measures that. That a pure virtual function can also have a body
was shown with only one example (`NoisyVehicle::warn`); which designs really need
that body was not generalized. That a line like `Vehicle v;` really produces a
compile error was not shown by running it in this lesson, because validation only
runs code that compiles successfully — this is a fact stated in the lesson text but
outside the code that was run.

#### Summary

- No object can be constructed directly from a class carrying a pure virtual
  function (`= 0`); only from derived classes that fill in that function.
- Each element in a `Vehicle*` array reaches its own concrete object, because the
  base type has no instance of its own at all — the class is **self**.
- Even an inherited function with a body supplied by the base class works with no
  object other than the concrete object it was called on.
- An abstract class (`Vehicle`) can carry data and offer functions with a common
  body; an interface (`Printable`) is purely signatures, carrying no data, no body
  at all.
- An object passed into an interface reference is the same object inside the
  function as it is outside — reference binding does not construct a copy here
  either.

#### Next Step

In this lesson, every concrete class filled in exactly one abstract base class or
interface; the base subobject always stood at the head of the derived object, just
like in the Inheritance lesson. The next lesson, Multiple Inheritance and the
Diamond Problem, measures the case where a class derives from **more than one**
base class at once — there, the second and subsequent base subobjects may no
longer stand at the head of the derived object, their addresses may not coincide
with the derived object's address. What is measured is again which object an
expression works with, but this time **which part** of the derived object the base
subobject stands in is also part of the question.

### Multiple Inheritance and the Diamond Problem

Source: https://academia.sh/en/courses/cpp-fundamentals/multiple-inheritance-and-the-diamond-problem

The measurement of how the second base subobject in multiple inheritance does not share the same address as the derived object, and how a common ancestor in diamond-shaped inheritance doubles without virtual inheritance.

The previous two lessons measured single inheritance: a derived object had exactly
one base subobject, and that subobject's address always coincided with the derived
object's address. This lesson covers the case where a class derives from **more
than one** base class at once. Does the first base subobject still stand at the
head of the derived object? Does the second one also share the same address? And if
the two base classes have a common ancestor, how many times does that ancestor take
up space inside the derived object?

#### In Multiple Inheritance the Second Base Subobject's Address Differs

`Triathlete` derives from two unrelated classes: `Swimmer` and `Runner`. Does the
first base subobject stand at the head of the derived object, does the second one
also share the same address?

```cpp
// multiple_inheritance_offset.cpp -- in multiple inheritance the first base is at the same address, the second is not
#include <iostream>

class Swimmer {
public:
    int style_ = 1;
};

class Runner {
public:
    int distance_ = 5;
};

class Triathlete : public Swimmer, public Runner {
public:
    int total_score_ = 0;
};

int main() {
    Triathlete t;

    std::cout << std::boolalpha;
    std::cout << "t and the first base Swimmer address the same "
              << (static_cast<void*>(&t) == static_cast<void*>(static_cast<Swimmer*>(&t))) << "\n";
    std::cout << "t and the second base Runner address the same "
              << (static_cast<void*>(&t) == static_cast<void*>(static_cast<Runner*>(&t))) << "\n";

    return 0;
}
```

```
t and the first base Swimmer address the same true
t and the second base Runner address the same false
```

**PS10.** `Triathlete` declares `Swimmer` first, `Runner` second in its inheritance
list — the compiler places the base subobjects in this order. The first base
subobject (`Swimmer`) stands at the head of `t`, so `&t` and
`static_cast<Swimmer*>(&t)` carry the same address, **true**. The second base
subobject (`Runner`) stands at an offset following the `Swimmer` subobject; `&t`
and `static_cast<Runner*>(&t)` are different addresses, **false**. In single
inheritance (the Inheritance lesson) the base subobject's address always coincided
with the derived object's, because there was only one base to carry; in multiple
inheritance this holds only for the **first** base. The class is **part**: both
base subobjects are a part of `t`, but only the first shares the same address.

#### The Diamond Problem: Two Separate Copies from a Common Ancestor

Let `Swimmer` and `Runner` have a common ancestor, `Living`. When `Triathlete`
derives from both, does reaching the `Living` subobject through `Swimmer` and
through `Runner` land on the same object, or two separate copies?

```cpp
// diamond_separate.cpp -- without virtual inheritance the common ancestor splits into two separate copies
#include <iostream>

class Living {
public:
    int health_ = 100;
};

class Swimmer : public Living {};
class Runner : public Living {};
class Triathlete : public Swimmer, public Runner {};

int main() {
    Triathlete t;

    Living* via_swimmer = static_cast<Living*>(static_cast<Swimmer*>(&t));
    Living* via_runner = static_cast<Living*>(static_cast<Runner*>(&t));

    std::cout << std::boolalpha;
    std::cout << "Living reached via Swimmer and via Runner the same "
              << (static_cast<void*>(via_swimmer) == static_cast<void*>(via_runner)) << "\n";
    std::cout << "Triathlete's size large enough to hold two separate Living "
              << (sizeof(Triathlete) >= 2 * sizeof(Living)) << "\n";

    return 0;
}
```

```
Living reached via Swimmer and via Runner the same false
Triathlete's size large enough to hold two separate Living true
```

**PS11.** `Swimmer` and `Runner` derive from `Living` through **ordinary**
(non-virtual) inheritance; each carries its own `Living` subobject. When
`Triathlete` derives from both, these two `Living` copies both enter `Triathlete`
— they do not merge. `via_swimmer` and `via_runner` carry different addresses,
**false**: these are two separate `Living` objects. `sizeof(Triathlete)` covering
at least two `Living` sizes confirms this in memory layout, **true**. This is the
**diamond problem**: writing `t.health_` would stop the compiler because it is
ambiguous which copy is meant, it only compiles with an explicit path like
`t.Swimmer::health_` or `t.Runner::health_` — this lesson never runs that ambiguous
line, it only shows the existence of the two copies through address and size
measurement. The class is **part**: `Triathlete` carries not one but two separate
parts of `Living`.

#### Virtual Inheritance: A Single Shared Base Subobject

If `Swimmer` and `Runner` derive from `Living` through **virtual** inheritance,
when `Triathlete` derives from both, is the `Living` subobject still split in two,
or reduced to a single shared object?

```cpp
// diamond_virtual.cpp -- virtual inheritance reduces the common ancestor to a single shared subobject
#include <iostream>

class Living {
public:
    int health_ = 100;
};

class Swimmer : virtual public Living {};
class Runner : virtual public Living {};
class Triathlete : public Swimmer, public Runner {};

int main() {
    Triathlete t;

    Living* via_swimmer = static_cast<Living*>(static_cast<Swimmer*>(&t));
    Living* via_runner = static_cast<Living*>(static_cast<Runner*>(&t));

    std::cout << std::boolalpha;
    std::cout << "Living reached via Swimmer and via Runner the same "
              << (static_cast<void*>(via_swimmer) == static_cast<void*>(via_runner)) << "\n";
    std::cout << "t.health_ and via_swimmer->health_ carry the same address "
              << (static_cast<void*>(&t.health_) == static_cast<void*>(&via_swimmer->health_)) << "\n";

    return 0;
}
```

```
Living reached via Swimmer and via Runner the same true
t.health_ and via_swimmer->health_ carry the same address true
```

**PS12.** The `virtual public Living` declaration tells `Swimmer` and `Runner`,
"do not construct your own `Living` copy, use the single copy shared by the
topmost derived class." When `Triathlete` derives from both, there is now only one
`Living` subobject — `via_swimmer` and `via_runner` carry the same address,
**true**. Thanks to this sharing, `t.health_` is no longer ambiguous either, it
compiles directly and points to the same shared object, **true**. The diamond
problem from the previous measurement — two separate `Living` copies — is gone
here, because both paths to `Living` converge on the same single object. The class
is **part**: `Triathlete` now carries not two but a single part of `Living`, and
this part is reached through both `Swimmer` and `Runner`.

#### Reaching Two Separate Copies by Qualified Name and Changing Only One

PS11 said that writing `t.health_` does not compile because it is ambiguous which
copy is meant, and that it only compiles with a qualified name like
`t.Swimmer::health_` or `t.Runner::health_`, but never ran that line. When only one
copy is changed with a qualified name, does the other copy really remain
unaffected?

```cpp
// multiple_inheritance_qualified_access.cpp -- in non-virtual inheritance two separate Living copies are reached by qualified name and one is changed
#include <iostream>

class Living {
public:
    int health_ = 100;
};

class Swimmer : public Living {};
class Runner : public Living {};
class Triathlete : public Swimmer, public Runner {};

int main() {
    Triathlete t;

    t.Swimmer::health_ = 70;

    std::cout << "t.Swimmer::health_ after change its value " << t.Swimmer::health_ << "\n";
    std::cout << "t.Runner::health_ value remaining unchanged " << t.Runner::health_ << "\n";
    std::cout << std::boolalpha
              << "t.Swimmer::health_ and t.Runner::health_ carry the same address "
              << (static_cast<void*>(&t.Swimmer::health_) == static_cast<void*>(&t.Runner::health_)) << "\n";

    return 0;
}
```

```
t.Swimmer::health_ after change its value 70
t.Runner::health_ value remaining unchanged 100
t.Swimmer::health_ and t.Runner::health_ carry the same address false
```

**PS32.** `t.Swimmer::health_ = 70;` uses the qualified name to explicitly tell the
compiler which copy is meant, and changes only that copy. `t.Runner::health_`
queried afterward is still its first value, **100** — the change made through
`Swimmer` never leaks into `Runner`'s own `Living` copy. The address comparison
confirms this directly: **false**, the two qualified accesses really reach two
separate objects. This directly proves what PS11 showed indirectly through memory
size: inside `Triathlete`, `Living` exists not once but twice, and qualified access
gives the programmer the ability to choose which of the two copies to work with —
manually making a decision the compiler cannot make on its own. The class is
**part**: `t.Swimmer::health_` and `t.Runner::health_` are two different parts of
`t`, capable of changing independently.

#### The Most Derived Class Calls the Virtual Base's Constructor

`Living` now has a non-default constructor that takes a parameter. `Swimmer` and
`Runner` each try to construct `Living` with their own value in their own
constructors, but `Triathlete` also constructs `Living` with a separate value in
its own constructor. In virtual inheritance, which constructor's value does the
shared `health_` carry?

```cpp
// diamond_virtual_constructor_chain.cpp -- the most derived class directly calls the virtual base's constructor, intermediate ones are bypassed
#include <iostream>

class Living {
public:
    explicit Living(int health) : health_(health) {
        std::cout << "Living constructor health=" << health_ << "\n";
    }
    int health_;
};

class Swimmer : virtual public Living {
public:
    Swimmer() : Living(1) {
        std::cout << "Swimmer constructor (its own Living(1) call will be bypassed)\n";
    }
};

class Runner : virtual public Living {
public:
    Runner() : Living(2) {
        std::cout << "Runner constructor (its own Living(2) call will be bypassed)\n";
    }
};

class Triathlete : public Swimmer, public Runner {
public:
    Triathlete() : Living(100), Swimmer(), Runner() {
        std::cout << "Triathlete constructor, shared health_ = " << health_ << "\n";
    }
};

int main() {
    Triathlete t;
    return 0;
}
```

```
Living constructor health=100
Swimmer constructor (its own Living(1) call will be bypassed)
Runner constructor (its own Living(2) call will be bypassed)
Triathlete constructor, shared health_ = 100
```

**PS33.** `Living constructor health=100` prints only **once**, `health=1` or
`health=2` never appears — the responsibility for calling the virtual base's
constructor falls not on the intermediate classes, but on the **most derived**
class. The `Living(1)` and `Living(2)` calls in `Swimmer`'s and `Runner`'s own
mem-initializer lists are ignored when constructed through `Triathlete`; these
lines would only take effect if `Swimmer` or `Runner` were constructed **on its
own** (without `Triathlete`). `Triathlete`'s own mem-initializer list's `Living(100)`
is the only call that really runs — this is why the shared `health_` is **100**.
Virtual bases, independent of their position in the inheritance chain, are always
initialized by the constructor of the topmost derived class; this is the
constructor-side counterpart of the "single shared object" principle measured as
PS12 — since the shared object is single, the call that constructs it also has to
be single. The class is **part**: `health_` is a single shared part of `t`, and
only the most derived class's constructor determines this part's value.

#### The Structural Cost of Virtual Inheritance: Fewer Copies, an Added Pointer

PS11 showed that `Living` took up space twice in the non-virtual diamond, PS12
showed it reduced to a single copy in the virtual diamond. Does the total object
size shrink by the same proportion as the copy count drops, or does virtual
inheritance's own overhead eat up part of this gain?

```cpp
// diamond_virtual_structural_cost.cpp -- comparing virtual inheritance's effect on object size against the same class set without it
#include <iostream>

class Living {
public:
    int health_ = 1;
};

class SwimmerPlain : public Living {};
class RunnerPlain : public Living {};
class TriathletePlain : public SwimmerPlain, public RunnerPlain {};

class SwimmerVirtual : virtual public Living {};
class RunnerVirtual : virtual public Living {};
class TriathleteVirtual : public SwimmerVirtual, public RunnerVirtual {};

int main() {
    std::cout << std::boolalpha
              << "is the virtual diamond's size smaller than the non-virtual diamond's: "
              << (sizeof(TriathleteVirtual) < sizeof(TriathletePlain)) << "\n";
    std::cout << "is the virtual diamond's size larger than a single Living (is there overhead): "
              << (sizeof(TriathleteVirtual) > sizeof(Living)) << "\n";
    std::cout << "is the non-virtual diamond's size at least two Living: "
              << (sizeof(TriathletePlain) >= 2 * sizeof(Living)) << "\n";

    return 0;
}
```

```
is the virtual diamond's size smaller than the non-virtual diamond's: false
is the virtual diamond's size larger than a single Living (is there overhead): true
is the non-virtual diamond's size at least two Living: true
```

**PS34.** The expectation was for the virtual diamond to come out smaller since the
copy count dropped, but the measurement does not confirm this: **false**. Because
`Living` has only a single `int` member, the cost of a copy is already small (a
few bytes); against this, `Swimmer` and `Runner` each carry a separate record
(a virtual base pointer or a similar mechanism, varies by compiler) to resolve how
to reach their own `Living` — two bases, two separate records. On this compiler,
the total cost of the added records outweighed the single `Living` copy that was
saved. The virtual diamond being larger than a single `Living` (**true**) was
already expected; what is instructive is that "fewer copies" and "a smaller object"
are not the same thing. This is the multiple-inheritance counterpart of the finding
measured as PS26 for virtual functions, "a vptr is added to every object": keeping
a shared thing (a method table / a base subobject) in one place loads a small but
non-zero bookkeeping cost onto the object — and this cost can even be larger than
the size of the copy that was eliminated. The class is **part**: the measured size
difference comes not from `t`'s virtual base subobject itself, but from the added
parts that carry the path leading to that subobject.

#### The Bounding Measurement

The virtual inheritance measured in this lesson showed the sharing of data
(`health_`) and the rule that only the most derived class calls the virtual base
class's constructor; but the measurement did not cover the extra indirection cost
virtual inheritance carries (every access being resolved through a virtual base
pointer) — it only measured address equality, not how many steps the resolution
takes. The case where `Triathlete` has its own virtual functions, and `Swimmer` and
`Runner` each define different functions with the same signature — a naming
collision and ambiguous redefinition — is outside this lesson's scope. Qualified
access (`t.Swimmer::health_`) was shown only under non-virtual inheritance; how
qualified access to the single shared copy behaves under virtual inheritance —
which would be indistinguishable from ordinary access, since the copy is already
single — was not additionally tested by this lesson.

#### Summary

- In multiple inheritance only the **first** base class's subobject shares the same
  address as the derived object; subsequent base subobjects stand at a different
  offset.
- If two base classes have a common ancestor and the inheritance is not virtual,
  that ancestor takes up space inside the derived object as **two separate
  copies** — the diamond problem.
- `sizeof` confirms the existence of two separate copies in memory size; the common
  ancestor object reached by two different paths carries different addresses.
- `virtual public` inheritance reduces the common ancestor to a **single**
  subobject shared by the topmost derived class; the ancestor reached by two paths
  now carries the same address.
- The expression measured in this lesson falls in the **part** class: the base
  subobject is a part of the derived object, but in multiple and diamond-shaped
  inheritance, that part's address and count change.

#### Next Step

What this lesson measured were always constructor and destructor calls that
completed in the normal flow; no constructor threw an error. The next lesson,
Exceptions, measures the case where a constructor is interrupted midway — throws
an error: how does an exception thrown before construction completes affect the
destruction of that object's already-constructed parts, and does an exception
object produce a **copy** as it is thrown with `throw` and caught with `catch`.
What is measured is again which object an expression works with, but this time the
question is the state of an object cut off in the middle of construction.

### Exceptions

Source: https://academia.sh/en/courses/cpp-fundamentals/exceptions

The measurement of how many times a thrown object is copied while being caught, which parts a construction cut short by an exception destroy, and how a temporary object is copied fewer times than a named local.

The previous four lessons measured constructors, destructors, and virtual calls that
completed in a normal flow. This lesson takes up the case where the flow is **cut
short**: when a function throws an error (`throw`), the thrown object can be copied
one or more times before it reaches the `catch` block; if the interruption happened in
the middle of a constructor, the already-constructed parts are destroyed, but the
object itself is never destroyed. The measurement question: how many times, and with
which object's copy, does an expression work?

#### Catching by Value Produces One More Copy Than Catching by Reference

`ErrorObject` increments a counter in its copy constructor. When we throw the same
named local object and catch it once by value and once by reference, how many copies
does the counter show?

```cpp
// exception_copy_counter.cpp — catching by value produces one more copy than catching by reference
#include <iostream>

class ErrorObject {
public:
    ErrorObject() = default;
    ErrorObject(const ErrorObject&) { ++copy_count; }
    static int copy_count;
};
int ErrorObject::copy_count = 0;

void throw_it() {
    ErrorObject e;
    throw e;
}

int main() {
    try {
        throw_it();
    } catch (ErrorObject e) {
        (void)e;
    }
    std::cout << "copy count after catch by value " << ErrorObject::copy_count << "\n";

    ErrorObject::copy_count = 0;
    try {
        throw_it();
    } catch (const ErrorObject& e) {
        (void)e;
    }
    std::cout << "copy count after catch by reference " << ErrorObject::copy_count << "\n";

    return 0;
}
```

```
copy count after catch by value 2
copy count after catch by reference 1
```

**PS13.** `throw e;` throws a named local — it produces one copy into the exception
storage (the first). `catch (ErrorObject e)` catches it **by value**, producing a
second copy: total **2**. `catch (const ErrorObject& e)` binds directly to the stored
object, producing no extra copy: total **1**. Class **copy**: catching by value adds
one more copy to the work of catching by reference.

#### An Exception That Cuts a Construction Short: The Already-Constructed Parts Are Destroyed, the Object Itself Is Not

`Composite`'s constructor throws an exception after constructing two `SubPart`
members. Are the already-constructed members destroyed? Does `Composite`'s own
destructor ever run?

```cpp
// exception_interrupted_construction.cpp — the already-constructed parts are destroyed, the object itself is never destroyed
#include <iostream>
#include <stdexcept>
#include <string>
#include <utility>

class SubPart {
public:
    explicit SubPart(std::string name) : name_(std::move(name)) {
        std::cout << name_ << " constructed\n";
    }
    ~SubPart() {
        std::cout << name_ << " destroyed\n";
    }
private:
    std::string name_;
};

class Composite {
public:
    Composite() : first_("first"), second_("second") {
        std::cout << "Composite body running, throwing exception\n";
        throw std::runtime_error("construction error");
    }
    ~Composite() {
        std::cout << "Composite destructor ran\n";
    }
private:
    SubPart first_;
    SubPart second_;
};

int main() {
    try {
        Composite c;
    } catch (const std::exception& e) {
        std::cout << "caught error: " << e.what() << "\n";
    }
    return 0;
}
```

```
first constructed
second constructed
Composite body running, throwing exception
second destroyed
first destroyed
caught error: construction error
```

**PS14.** `first_` and `second_` are constructed in the member initializer list. The
exception thrown in the body cuts the constructor short: `Composite` **never
completes**. As the stack unwinds, the members constructed up to that point are
destroyed in reverse order — first `second_`, then `first_` — but "Composite
destructor ran" is never printed: the destructor is only called if the constructor has
**completed**. Class **copy** does not appear directly here, but `catch (const
std::exception& e)` catches by reference and produces no extra copy.

#### A Temporary Object Is Copied Fewer Times Than a Named Local

In PS13, throwing a named local and catching it by value gave a copy count of **2**.
Does that number change if a temporary is thrown directly (`throw ErrorObject();`) and
still caught by value?

```cpp
// exception_temporary_copy.cpp — throwing a temporary object copies fewer times than a named local
#include <iostream>

class ErrorObject {
public:
    ErrorObject() = default;
    ErrorObject(const ErrorObject&) { ++copy_count; }
    static int copy_count;
};
int ErrorObject::copy_count = 0;

void throw_temporary() {
    throw ErrorObject();
}

int main() {
    try {
        throw_temporary();
    } catch (ErrorObject e) {
        (void)e;
    }
    std::cout << "copy count when throwing a temporary (catch by value) "
              << ErrorObject::copy_count << "\n";

    return 0;
}
```

```
copy count when throwing a temporary (catch by value) 1
```

**PS15.** `throw_temporary` does not construct a named local; it constructs and throws
a temporary (prvalue) directly. In C++17, an exception object initialized from a
temporary (prvalue) is constructed directly in the exception storage without calling
the copy constructor, so the first copy drops out. The only remaining copy is the one
from catching by value: total **1**, one less than PS13's **2**. Class **copy**:
whether the thrown expression is a named local or a temporary changes the copy count.

#### Stack Unwinding Spans Multiple Frames: Each Layer Destroys Its Own Locals

PS14 measured a construction interrupted inside a single constructor. If an exception
is thrown at the innermost of several nested function calls, are the local objects in
the intermediate frames also destroyed by the same stack-unwinding mechanism, and in
what order?

```cpp
// exception_stack_unwinding.cpp — in multi-frame stack unwinding, each frame destroys its own locals in reverse order
#include <iostream>
#include <stdexcept>
#include <string>
#include <utility>

class Tracker {
public:
    explicit Tracker(std::string name) : name_(std::move(name)) {
        std::cout << name_ << " constructed\n";
    }
    ~Tracker() {
        std::cout << name_ << " destroyed (during stack unwinding)\n";
    }
private:
    std::string name_;
};

void third_level() {
    Tracker t3("third level");
    throw std::runtime_error("error deep inside");
}

void second_level() {
    Tracker t2("second level");
    third_level();
}

void first_level() {
    Tracker t1("first level");
    second_level();
}

int main() {
    try {
        first_level();
    } catch (const std::exception& e) {
        std::cout << "caught error: " << e.what() << "\n";
    }
    return 0;
}
```

```
first level constructed
second level constructed
third level constructed
third level destroyed (during stack unwinding)
second level destroyed (during stack unwinding)
first level destroyed (during stack unwinding)
caught error: error deep inside
```

**PS35.** The locals of the three frames are printed in construction order; destruction
happens in reverse: first `t3`, then `t2`, then `t1`. Stack unwinding destroys the
locals of **every** frame it passes through until it reaches the `catch` — the rule from
PS14's single constructor, generalized to the entire call stack. Class **copy** does
not appear, but the mechanism is the same.

#### throw; Preserves the Original Object, throw e; Slims It to the Static Type

There are two ways to rethrow a caught exception: the parameterless `throw;` and
`throw e;`, which throws the caught variable. Do they carry the same exception out?

```cpp
// exception_throw_vs_throw_e.cpp — throw; preserves the original type, throw e; slims it to the parameter's static type
#include <iostream>
#include <stdexcept>

class BaseError : public std::runtime_error {
public:
    BaseError() : std::runtime_error("base error") {}
};

class DerivedError : public BaseError {
public:
    DerivedError() = default;
};

void rethrow_original() {
    try {
        throw DerivedError();
    } catch (BaseError&) {
        throw; // rethrows the caught object as is, with its dynamic type
    }
}

void rethrow_slimmed() {
    try {
        throw DerivedError();
    } catch (BaseError& e) {
        throw e; // constructs a new object from e's static type (BaseError)
    }
}

int main() {
    try {
        rethrow_original();
    } catch (DerivedError&) {
        std::cout << "after throw;, caught as DerivedError\n";
    } catch (BaseError&) {
        std::cout << "after throw;, caught as BaseError\n";
    }

    try {
        rethrow_slimmed();
    } catch (DerivedError&) {
        std::cout << "after throw e;, caught as DerivedError\n";
    } catch (BaseError&) {
        std::cout << "after throw e;, caught as BaseError\n";
    }

    return 0;
}
```

```
after throw;, caught as DerivedError
after throw e;, caught as BaseError
```

**PS36.** `throw;` rethrows the caught object as is; the outer `catch` still catches it
as **`DerivedError`** — the dynamic type is preserved. `throw e;` instead constructs a
new object from `e`'s **static** type (`BaseError`); `catch (DerivedError&)` no longer
matches — the same root as the object slicing in PS21. Class **copy**: `throw e;`
carries a copy constructed from `e`'s static type, not the original's.

#### Catching the Base Class by Value Slices the Derived Exception

`DerivedError` overrides the virtual function `type_name()`. When the same object is
caught once by value and once by reference as `BaseError`, which version does
`type_name()` reach?

```cpp
// exception_catch_by_value_slicing.cpp — a derived exception caught by value into the base is sliced, caught by reference is not
#include <iostream>
#include <stdexcept>

class BaseError : public std::exception {
public:
    virtual const char* type_name() const { return "BaseError"; }
};

class DerivedError : public BaseError {
public:
    const char* type_name() const override { return "DerivedError"; }
};

void throw_derived() {
    throw DerivedError();
}

int main() {
    try {
        throw_derived();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcatch-value="
    } catch (BaseError e) { // the compiler deliberately warns about catching by value here, the measurement shows exactly this behavior
#pragma GCC diagnostic pop
        std::cout << "type_name() of the object caught by value: " << e.type_name() << "\n";
    }

    try {
        throw_derived();
    } catch (const BaseError& e) {
        std::cout << "type_name() of the object caught by reference: " << e.type_name() << "\n";
    }

    return 0;
}
```

```
type_name() of the object caught by value: BaseError
type_name() of the object caught by reference: DerivedError
```

**PS37.** `catch (BaseError e)` catches by value: the object is copied into a new
object of type `BaseError` — slicing similar to PS21, `type_name()` reaches
**`BaseError`**. `catch (const BaseError& e)` binds directly to the stored
`DerivedError`, does not slice: **`DerivedError`**. This is why exception hierarchies
are almost always caught **by reference**. Class **copy**: the object produced by
`catch (BaseError e)` is a copy of only the original's `BaseError` part.

#### Three Levels of Exception Guarantee: The Strong Level Preserves State, the Basic Level May Change It

After a function that throws an exception, an object's state can be in one of three
levels: the **strong guarantee** (returns to the state before the call), the **basic
guarantee** (valid but may have changed), and the **no-throw guarantee** (the next
measurement). Two addition functions that cross the same limit — one written with the
strong guarantee, one with the basic guarantee — how do they differ after a failed
call?

```cpp
// exception_guarantee_levels.cpp — the strong guarantee does not change state after a failed call, the basic guarantee may
#include <iostream>
#include <stdexcept>

class Counter {
public:
    void strong_add(int amount) {
        int new_value = value_ + amount; // computed in a local variable, value_ has not changed yet
        if (new_value > 100) {
            throw std::runtime_error("limit exceeded");
        }
        value_ = new_value; // assignment happens only once success is certain
    }

    void basic_add(int amount) {
        value_ += amount / 2;             // the first half is applied directly first
        if (value_ + amount / 2 > 100) {
            throw std::runtime_error("limit exceeded");
        }
        value_ += amount / 2;             // then the remaining half
    }

    int value() const { return value_; }

private:
    int value_ = 90;
};

int main() {
    Counter c1;
    try {
        c1.strong_add(20);
    } catch (const std::exception&) {
        std::cout << std::boolalpha
                  << "strong_add failed, did the value change: "
                  << (c1.value() != 90) << "\n";
    }

    Counter c2;
    try {
        c2.basic_add(20);
    } catch (const std::exception&) {
        std::cout << std::boolalpha
                  << "basic_add failed, did the value change: "
                  << (c2.value() != 90) << "\n";
    }

    return 0;
}
```

```
strong_add failed, did the value change: false
basic_add failed, did the value change: true
```

**PS38.** `strong_add` performs the limit check in a **local variable** and only
assigns to `value_` once success is certain; `value_` is never touched: **false** —
the strong guarantee. `basic_add` applies the limit in **two steps**, wedging the check
between them; at the moment it throws, `value_` has already partly changed: **true** —
the basic guarantee. The third level is covered in the next measurement via
`noexcept`. Class **itself**: the difference is not in the object's identity, but in
the state the call leaves it in.

#### Copy, Swap, Swap-Exchange: Earning the Strong Guarantee From Structure

Instead of writing the assignment operator by hand, taking the parameter **by value**
and swapping it with an `exchange` function is another well-known pattern that provides
the strong guarantee. Does it produce the correct result in a normal assignment and in
self-assignment (`c = c;`)?

```cpp
// exception_copy_swap_exchange.cpp — the copy-swap-exchange pattern gives the correct result in normal assignment and self-assignment
#include <iostream>
#include <string>
#include <utility>

class Buffer {
public:
    explicit Buffer(std::string data) : data_(std::move(data)) {}
    Buffer(const Buffer& other) : data_(other.data_) {}

    friend void exchange(Buffer& a, Buffer& b) noexcept {
        using std::swap;
        swap(a.data_, b.data_);
    }

    Buffer& operator=(Buffer other) { // taken by value: the copy is made at the call itself
        exchange(*this, other);
        return *this;
    } // other is destroyed here, taking the old data_ with it

    const std::string& data() const { return data_; }

private:
    std::string data_;
};

int main() {
    Buffer a("first");
    Buffer b("second");
    a = b;
    std::cout << "after assignment a: " << a.data() << ", b: " << b.data() << "\n";

    Buffer c("third");
    c = c;
    std::cout << "after self-assignment c: " << c.data() << "\n";

    return 0;
}
```

```
after assignment a: second, b: second
after self-assignment c: third
```

**PS39.** `operator=(Buffer other)` takes the parameter **by value**; `other` is
constructed as an independent copy at call time — the copy completes **before** the
body runs, the only place that can throw. The body only calls the `noexcept`
`exchange`: this ordering gives the strong guarantee automatically — if the copy fails,
`*this` is never changed. In self-assignment (`c = c;`), no special check is needed;
since `other` is an independent copy, the result is still **third**. Class **copy**:
the guarantee rests on making a separate copy before the assignment.

#### noexcept: A No-Throw Contract and the Move Choice on Reallocation

When `std::vector` exceeds its capacity, it reallocates and either moves or copies the
old elements. The standard requires copying if the move constructor is **not**
`noexcept` — an exception thrown mid-move during reallocation could leave elements
unrecoverable. Do two classes, one with a `noexcept` move constructor and one without,
really behave differently when grown with `emplace_back`?

```cpp
// exception_noexcept_vector_choice.cpp — a noexcept-marked move constructor takes precedence over copying during vector reallocation
#include <iostream>
#include <vector>

class SafeMove {
public:
    SafeMove() = default;
    SafeMove(const SafeMove&) { ++copy_count; }
    SafeMove(SafeMove&&) noexcept { ++move_count; }
    static int copy_count;
    static int move_count;
};
int SafeMove::copy_count = 0;
int SafeMove::move_count = 0;

class UnsafeMove {
public:
    UnsafeMove() = default;
    UnsafeMove(const UnsafeMove&) { ++copy_count; }
    UnsafeMove(UnsafeMove&&) { ++move_count; } // not noexcept
    static int copy_count;
    static int move_count;
};
int UnsafeMove::copy_count = 0;
int UnsafeMove::move_count = 0;

int main() {
    {
        std::vector<SafeMove> v;
        v.reserve(1);
        for (int i = 0; i < 5; ++i) {
            v.emplace_back();
        }
    }
    std::cout << std::boolalpha
              << "did reallocation with a noexcept move constructor use any copies: "
              << (SafeMove::copy_count > 0) << "\n";
    std::cout << "did reallocation with a noexcept move constructor use moves: "
              << (SafeMove::move_count > 0) << "\n";

    {
        std::vector<UnsafeMove> v;
        v.reserve(1);
        for (int i = 0; i < 5; ++i) {
            v.emplace_back();
        }
    }
    std::cout << "did reallocation with a non-noexcept move constructor use any copies: "
              << (UnsafeMove::copy_count > 0) << "\n";

    return 0;
}
```

```
did reallocation with a noexcept move constructor use any copies: false
did reallocation with a noexcept move constructor use moves: true
did reallocation with a non-noexcept move constructor use any copies: true
```

**PS40.** `SafeMove`'s move constructor is `noexcept`: `vector` never uses copies while
reallocating — `copy_count > 0` is **false**, `move_count > 0` is **true**.
`UnsafeMove`'s is not `noexcept`: `vector` chooses to copy — `copy_count > 0` is
**true**. `noexcept` is not just a documentation note; the standard library runs
**different code** based on this contract; breaking the promise and throwing triggers
`std::terminate`, and that path was not run here. Class **copy**: the presence of
`noexcept` determines whether elements are moved with a copy or a move.

#### The Bounding Measurement

In this lesson, exceptions were always caught with a single or a sequence of `catch`
blocks; catching every type with `catch (...)` and **partial** matching within the same
hierarchy were out of scope. That a `noexcept`-marked function actually throwing
triggers `std::terminate` was not measured — since the program could not end cleanly,
it cannot be shown in the sandbox; only the case where the contract is kept was
measured. The copy-swap-exchange pattern's core guarantee — that if the copy
constructor **itself** throws, `*this` remains untouched — was only addressed
indirectly here; the case where the copy constructor actually throws was not run
separately.

#### Summary

- `throw e;` copies a named local variable into the exception storage once;
  `catch (ErrorObject e)` catches this stored object by value, producing a second copy.
- `catch (const ErrorObject&)` binds directly to the stored object, producing no extra
  copy.
- An exception thrown in a constructor's body destroys the members constructed up to
  that point in reverse construction order, but never calls the object's own
  destructor — because the constructor did not complete.
- Throwing a temporary object directly (`throw ErrorObject();`) produces one fewer copy
  than throwing a named local.
- The expression this lesson measures falls in the **copy** class: how an exception is
  thrown and caught directly determines how many copies end up being made.

#### Next Step

In this lesson, `ErrorObject::copy_count` shared the same counter across every call as
a `static` member. The next lesson, Namespaces and Code Organization, measures how two
symbols with the same name are separated by namespaces, and whether `static`/`extern`
linkage confines a symbol to a single file or shares it across files — again the
question of which symbol an expression works with, but now across file boundaries
rather than class boundaries.

### Namespaces and Code Organization

Source: https://academia.sh/en/courses/cpp-fundamentals/namespaces-and-code-organization

The measurement of how two symbols with the same name are separated by namespaces, and that a using declaration and a namespace alias are not a new symbol but an access path to an existing one.

The previous lesson showed that `ErrorObject::copy_count`, a `static` member defined
in a single translation unit, shared the same counter across every call — the
measurement was within class and object boundaries. This lesson moves the boundary up
a level: **namespaces**. Two different libraries or modules may want to use the same
name (`compute`, `Vehicle`); namespaces resolve this collision by placing each symbol
inside its own namespace. This is a different axis from the "which object does this
work with" question measured since the start of the course: here it is not the object
but **the symbol itself** — which definition a name corresponds to — that is measured.
The measurement question follows a similar pattern — which symbol does an expression
work with — but now it is not a class or an object being measured, but a name and the
namespace holding it. In terms of code organization, the practical consequence is
simple: a library groups related names under a single namespace, both preventing
collisions and making it clear to the reader where those names come from.

#### Two Different Symbols With the Same Name: Namespaces Separate Them

Both the `land` and `sea` namespaces define a function named `compute`. When called by
qualified name (`land::compute`, `sea::compute`), are these really two different
functions, or do they somehow resolve to the same symbol?

```cpp
// namespace_same_name.cpp — namespaces separate two different symbols with the same name
#include <iostream>

namespace land {
int compute(int base) {
    return base * 2;
}
}

namespace sea {
int compute(int base) {
    return base * 3;
}
}

int main() {
    std::cout << "land::compute(5) result " << land::compute(5) << "\n";
    std::cout << "sea::compute(5) result " << sea::compute(5) << "\n";

    int (*land_ptr)(int) = land::compute;
    int (*sea_ptr)(int) = sea::compute;

    std::cout << std::boolalpha
              << "are land::compute and sea::compute the same function "
              << (land_ptr == sea_ptr) << "\n";

    return 0;
}
```

```
land::compute(5) result 10
sea::compute(5) result 15
are land::compute and sea::compute the same function false
```

**PS16.** `land::compute(5)` and `sea::compute(5)` give different results (10 and 15) —
same name, two independent bodies. The `land_ptr == sea_ptr` comparison confirms this
at the function pointer level: **false**, because the two really are different
symbols. Without namespaces, two `compute` functions with the same signature could not
be defined in the same translation unit; it would be a redefinition error. (The
`static`/`extern` linkage measured in M11/K03's Building Libraries lesson determined
whether a symbol was confined to one file or shared across files; here a namespace
separates two symbols with the same linkage **by name** — a different mechanism for
the same problem.) Class **itself**: a qualified name (`land::compute`) always reaches
the particular symbol in its own namespace, never crossing paths with a same-named
symbol in another namespace.

#### A using Declaration Does Not Establish a New Symbol, It Opens Access to an Existing One

When `using land::compute;` is written inside the `use_it` function, is the resulting
local `compute` name a new symbol, or an access path opened to `land::compute`?

```cpp
// namespace_using.cpp — a using declaration is not a new symbol, it opens an access path to an existing one
#include <iostream>

namespace land {
int compute(int base) {
    return base * 2;
}
}

void use_it() {
    using land::compute;
    int (*local_ptr)(int) = compute;
    int (*direct_ptr)(int) = land::compute;

    std::cout << std::boolalpha
              << "is compute reached via using the same as land::compute directly "
              << (local_ptr == direct_ptr) << "\n";
}

int main() {
    use_it();
    return 0;
}
```

```
is compute reached via using the same as land::compute directly true
```

**PS17.** `using land::compute;` allows the name `compute` to be used unqualified
inside `use_it`, but what it points to does not change — `local_ptr` (taken
unqualified) and `direct_ptr` (taken directly via `land::compute`) carry the same
function pointer: **true**. A `using` declaration does not produce a copy, nor does it
establish a new function; it only tells the compiler "let this unqualified name
correspond to that qualified symbol." Class **itself**: after `using`, the unqualified
call reaches exactly the same symbol as the qualified call.

#### Two Different Access Paths to a Nested Namespace

`company::fleet` is a nested namespace. `vehicle_count` is reached by one function
through the fully qualified name, and by another through a namespace alias
(`namespace f = company::fleet;`). Do both reach the same variable?

```cpp
// namespace_nested.cpp — a fully qualified name and an alias reach the same variable
#include <iostream>

namespace company::fleet {
int vehicle_count = 12;
}

void* first_access() {
    return static_cast<void*>(&company::fleet::vehicle_count);
}

void* second_access() {
    namespace f = company::fleet;
    return static_cast<void*>(&f::vehicle_count);
}

int main() {
    std::cout << std::boolalpha
              << "are the variable reached by fully qualified name and by alias the same "
              << (first_access() == second_access()) << "\n";
    return 0;
}
```

```
are the variable reached by fully qualified name and by alias the same true
```

**PS18.** `namespace company::fleet { ... }` opens two levels in a single line using
C++17's nested namespace syntax. `first_access` reaches `vehicle_count` by the fully
qualified name; `second_access` first defines `f` as an **alias** of `company::fleet`,
then reaches it through `f::vehicle_count`. Comparing the addresses returned by the two
access paths gives **true**: an alias, just like a `using` declaration, does not
establish a new variable, it opens a shortened path to the one that already exists.
Class **itself**: however different the access path looks (full name, alias, `using`),
all of them reach the same particular symbol.

#### The Unnamed Namespace: Confining a Symbol to Its Own Unit

Two different translation units each define a function named `value` inside their own
unnamed (anonymous) namespace. When the two units are compiled and linked separately,
does this name collision produce a link error, or does each unit keep its own
definition?

```cpp
// namespace_internal_linkage_unit_a.cpp — a symbol inside an unnamed namespace is specific to this unit, not visible from outside
namespace {
int value() { return 111; }
}

int unit_a_value() {
    return value();
}
```

```cpp
// namespace_internal_linkage_unit_b.cpp — another same-named unnamed namespace symbol, in a different unit, does not collide
namespace {
int value() { return 222; }
}

int unit_b_value() {
    return value();
}
```

```cpp
// namespace_internal_linkage_main.cpp — the same-named unnamed namespace symbol in two different units compiles and links without colliding
#include <iostream>

int unit_a_value();
int unit_b_value();

int main() {
    std::cout << "unit_a_value() result " << unit_a_value() << "\n";
    std::cout << "unit_b_value() result " << unit_b_value() << "\n";
    return 0;
}
```

```
unit_a_value() result 111
unit_b_value() result 222
```

**PS41.** Both units call their own `value()`, and each returns its own value —
**111** and **222**, with no crossover at all. Every symbol inside an unnamed
namespace is turned by the compiler into a name specific to that translation unit,
invisible from outside; this is why two separate `.cpp` files can each define a
`value()` with the same name without the linker seeing it as a collision. This gives
the same result as the `static` linkage measured in `M11/K03` — confining a symbol to
a single file — but the unnamed namespace provides this with the same syntax not only
for functions but for classes and variables as well. Class **itself**: the name
`value` inside `unit_a_value()` reaches only `unit_a`'s own definition, never crossing
with `unit_b`'s `value`.

#### A using Declaration Opens a Single Symbol, a using Directive Opens the Whole Namespace

PS17's `using land::compute;` was a **declaration** — it made a single symbol
accessible unqualified. `using namespace land;` is a **directive** — it opens the
entire namespace. If only one of the same namespace's two functions (`compute`,
`double_it`) is brought in with a declaration, does the other still need a qualified
name; does the directive make both reachable unqualified?

```cpp
// namespace_declaration_vs_directive.cpp — a using declaration opens a single symbol, a using directive opens the whole namespace
#include <iostream>

namespace land {
int compute(int base) { return base * 2; }
int double_it(int base) { return base * 2; }
}

void declaration_only() {
    using land::compute; // only compute becomes accessible unqualified
    std::cout << "declaration_only: compute(5) = " << compute(5) << "\n";
    std::cout << "declaration_only: land::double_it(5) = " << land::double_it(5) << "\n";
}

void whole_namespace() {
    using namespace land; // all of land's symbols become accessible unqualified
    std::cout << "whole_namespace: compute(5) = " << compute(5) << "\n";
    std::cout << "whole_namespace: double_it(5) = " << double_it(5) << "\n";
}

int main() {
    declaration_only();
    whole_namespace();
    return 0;
}
```

```
declaration_only: compute(5) = 10
declaration_only: land::double_it(5) = 10
whole_namespace: compute(5) = 10
whole_namespace: double_it(5) = 10
```

**PS42.** Inside `declaration_only`, `compute(5)` can be called unqualified, but
`double_it` **must** still be qualified as `land::double_it(5)` — the declaration only
opens the symbol you named, it does not touch the rest of `land`. Inside
`whole_namespace`, after `using namespace land;`, both `compute(5)` and `double_it(5)`
can be called unqualified — the directive adds the **entire** namespace to the lookup
scope. Both reach the same two functions (both return 10); the difference is not in
the result, but in which names become usable unqualified. Class **itself**: the
declaration and the directive open access to the same symbols with different **scope
widths**, they do not change the symbols themselves.

#### Multi-Unit Header/Source Separation: inline Permits Repeating the Same Definition

A function written in a header file and included into more than one `.cpp` file ends
up **repeatedly** defined, once per included file — an ordinary function finds this in
violation of the one-definition rule (ODR). Does the `inline` keyword really legitimize
this repetition?

```cpp
// namespace_inline_header_unit1.cpp — an inline function, assumed to come from a header file, is defined in this unit
inline int twice(int x) {
    return x * 2;
}

int unit1_twice(int x) {
    return twice(x);
}
```

```cpp
// namespace_inline_header_unit2.cpp — a token-for-token identical definition of the same inline function is repeated in another unit
inline int twice(int x) {
    return x * 2;
}

int unit2_twice(int x) {
    return twice(x);
}
```

```cpp
// namespace_inline_header_main.cpp — the identical inline definition in two different units compiles and links without violating the one-definition rule
#include <iostream>

int unit1_twice(int x);
int unit2_twice(int x);

int main() {
    std::cout << "unit1_twice(21) result " << unit1_twice(21) << "\n";
    std::cout << "unit2_twice(21) result " << unit2_twice(21) << "\n";
    return 0;
}
```

```
unit1_twice(21) result 42
unit2_twice(21) result 42
```

**PS43.** Two separate translation units define `twice` **independently of each
other**, but **token-for-token identically** — this simulates a header file being
included into two `.cpp` files. The program compiles and links successfully, and both
units produce the same result: **42**. `inline` opens an exception to the one-
definition rule: a function can be defined in more than one translation unit, **as long
as every definition is exactly the same**. This is the exact opposite strategy of the
unnamed namespace's (PS41) solution — the unnamed namespace prevented collision by
**hiding** the symbol, `inline` prevents it by **sharing** the symbol and turning
sameness of the definitions into a contract. If the two definitions differed (say, one
returned `x * 2` and the other `x * 3`), the program would be ill-formed according to
the standard, and the compiler would not be required to diagnose it (no diagnostic
required) — a compiler cannot always catch this, so it was never run here; only the
case that follows the rule, where the identical definition is repeated, was measured.
Class **itself**: `twice` corresponds to the same symbol in both units, not multiple
copies but the same contract expressed in two places.

#### The Contrast Between static and a Shared (extern) Symbol

PS41 provided internal linkage via the unnamed namespace. The `static` keyword gives
the same effect directly at file scope. Does making a function `static` really confine
it to its file; conversely, can an ordinary function defined without `static` or an
unnamed namespace (whose default linkage is `extern`) really be called from another
unit?

```cpp
// namespace_linkage_unit1.cpp — a static, internally-linked symbol is specific to this unit, an extern (default) symbol is open to the outside
static int internal_value() {
    return 7;
}

int external_value() {
    return 700;
}

int unit1_use_internal_value() {
    return internal_value();
}
```

```cpp
// namespace_linkage_unit2.cpp — another same-named static symbol, in a different unit, exists without colliding
static int internal_value() {
    return 9;
}

int unit2_use_internal_value() {
    return internal_value();
}
```

```cpp
// namespace_linkage_main.cpp — a static symbol is confined to each unit, an extern (default) symbol can be called directly from any unit
#include <iostream>

int unit1_use_internal_value();
int unit2_use_internal_value();
int external_value();

int main() {
    std::cout << "unit1_use_internal_value() result " << unit1_use_internal_value() << "\n";
    std::cout << "unit2_use_internal_value() result " << unit2_use_internal_value() << "\n";
    std::cout << "external_value() called directly from the main unit, result " << external_value() << "\n";
    return 0;
}
```

```
unit1_use_internal_value() result 7
unit2_use_internal_value() result 9
external_value() called directly from the main unit, result 700
```

**PS44.** `unit1` and `unit2`'s own `static internal_value()`s give exactly the same
result as PS41's unnamed namespace example: **7** and **9**, with no crossover —
`static` gives a function at file scope internal linkage, just like the unnamed
namespace. But `external_value()` is not inside a `static` or an unnamed namespace at
all; its default linkage is **extern**, and this is why it can be called **directly**
from the main unit just by being declared (`int external_value();`) — **700**, reaching
the single object defined in its own unit. All three mechanisms were measured in this
lesson: the unnamed namespace (PS41) and `static` (here) confine a symbol to its file,
`inline` (PS43) shares the symbol while requiring the definitions to stay identical,
and ordinary `extern` linkage gathers the symbol into a single definition accessible
from anywhere. Class **itself**: all three mechanisms solve the same name-collision
problem by changing the symbol's **visibility scope**; the symbol itself always stays
particular.

#### The Bounding Measurement

The multi-unit examples measured in this lesson simulated including an actual header
file (`.h`) into multiple `.cpp` files by manually copying the same definition into
two source units instead — the preprocessor's own textual copying during `#include`
was not separately measured in this lesson. Argument-dependent lookup (ADL, the
mechanism that finds an operator like `std::cout <<` without a qualifying name) is
outside this lesson's scope; here every call was made either with a qualified name or
with an explicit `using`. The case where the one-definition rule is **violated** — two
different, non-`inline` definitions in two units colliding under the same externally
visible name — results in a link error or undefined behavior and so was never run;
only the cases that **follow** the rule were measured. A namespace itself (independent
of its functions) being extended across multiple files with multiple `namespace land {
... }` blocks was also not shown; here namespaces always stayed defined within a single
file, only the linkage kind of the symbols **inside** them was tested across multiple
units.

#### Summary

- Same-named functions in two different namespaces are independent symbols; a
  qualified name (`land::compute`) always reaches its own definition.
- A function pointer comparison confirms this: `land::compute` and `sea::compute` are
  not the same function.
- A `using` declaration does not establish a new symbol; it binds the unqualified name
  to an existing qualified symbol — class **itself**.
- A namespace alias (`namespace f = company::fleet;`) works on the same principle: it
  does not establish a new variable, it opens a shortened access path to the existing
  one.
- The fully qualified name, `using`, and the alias — all three reach the same
  particular symbol; only the spelling differs.

#### Next Step

`static_cast<void*>(...)` was used frequently throughout this lesson, but what
`static_cast` guarantees, or how a class can define its own conversion rules, was
never opened up — it was only used as a tool for comparing addresses. The course's
closing lesson, Type Conversion Operators, takes this up directly: it measures how a
class can offer an implicit or explicit conversion to a type other than its own, and
whether the value produced when such a conversion is invoked works with the original
object or with a new object derived from it.

### Type Conversion Operators

Source: https://academia.sh/en/courses/cpp-fundamentals/type-conversion-operators

The measurement of whether static_cast, dynamic_cast, const_cast, and reinterpret_cast access a reference as a part of an existing object or as a copy in a new one, depending on the target type.

The previous lesson showed that a `using` declaration and a namespace alias do not
construct a new symbol, but open a local access path to an existing symbol — the
measurement was at the namespace boundary. This lesson lowers the boundary one more
level: **type conversion operators**. When we convert a `Thermometer` object with
`static_cast` to the base `Measurer`, the question stays the same — which object
did `t` refer to, and which object does the conversion give? The answer does not
depend on the operator's name but on the **target type**: the same `static_cast`
refers to the subobject inside `t` when the target is a reference; it constructs a
brand new object when the target is a value.

#### A Reference Converted to the Base

`Thermometer` derives from `Measurer`. When we convert `t` to `const Measurer&`
with `static_cast`, the compiler does not construct a new object; it produces a
reference that views the `Measurer` subobject inside `t` through a narrower type.
This reference's address stays within the same range as `t`'s address — because
the base class subobject is a part of the derived object.

```cpp
// base-reference.cpp -- does static_cast reference conversion construct a new object
#include <cstdio>

class Measurer {
public:
    virtual ~Measurer() = default;
    void read() const { std::printf("measurer read called\n"); }
};

class Thermometer : public Measurer {
public:
    int degree() const { return degree_; }
private:
    int degree_ = 20;
};

int main() {
    Thermometer t;
    const Measurer& base = static_cast<const Measurer&>(t);

    base.read();
    std::printf("same address %s\n",
        (static_cast<const void*>(&base) == static_cast<const void*>(&t)) ? "yes" : "no");
    return 0;
}
```

```text
measurer read called
same address yes
```

**PS45.** `base` refers to the `Measurer` subobject inside `t`; the `read()` call
does not operate on a new object, but on `t`'s own part. `&base` and `&t` coming
out at the same address range confirms this — the conversion did not call a
constructor, it only narrowed the type viewing `t`. This expression's class is
**part**.

#### Value Conversion: Same Operator, Different Class

Now convert the same `t`, this time with the target being a **value** instead
of a reference: `static_cast<Measurer>(t)`. The operator name is the same —
`static_cast` — but the target type is no longer a reference, it is `Measurer`
itself. Here the compiler copies `t`'s `Measurer` subobject and constructs a
brand new, independent `Measurer` object.

```cpp
// value-conversion.cpp -- does static_cast construct a new object with a value target
#include <cstdio>

class Measurer {
public:
    virtual ~Measurer() = default;
    void read() const { std::printf("measurer read called\n"); }
};

class Thermometer : public Measurer {
public:
    int degree() const { return degree_; }
private:
    int degree_ = 20;
};

int main() {
    Thermometer t;
    Measurer copy = static_cast<Measurer>(t);

    copy.read();
    std::printf("same address %s\n",
        (static_cast<const void*>(&copy) == static_cast<const void*>(&t)) ? "yes" : "no");
    return 0;
}
```

```text
measurer read called
same address no
```

**PS46.** `copy` is a new `Measurer` object independent of `t`; `&copy` and `&t`
come out at different addresses. Despite being the same operator as
`static_cast<const Measurer&>(t)` in the previous section, this is a completely
different result: here `t`'s part specific to `Thermometer` (`degree_`) is
discarded, and only the `Measurer` part is copied — this is **object slicing**.
This expression's class is **copy**.

#### Dynamic Conversion: A Decision Based on the Real Type

`static_cast` trusts the target type blindly; it decides at compile time.
`dynamic_cast`, however, looks at the object's real type at run time — if the
object behind the base reference is not actually of the requested derived type,
the conversion fails. Failure gives `nullptr` for a pointer target; it throws an
exception for a reference target.

```cpp
// dynamic-conversion.cpp -- what does dynamic_cast give on a failed downcast
#include <cstdio>
#include <typeinfo>

class Measurer {
public:
    virtual ~Measurer() = default;
};

class Thermometer : public Measurer {
public:
    int degree() const { return degree_; }
private:
    int degree_ = 20;
};

class Barometer : public Measurer {
public:
    int pressure() const { return pressure_; }
private:
    int pressure_ = 1013;
};

int main() {
    Thermometer t;
    Measurer& base = t;

    Barometer* p = dynamic_cast<Barometer*>(&base);
    std::printf("pointer conversion succeeded %s\n", p ? "yes" : "no");

    try {
        Barometer& b = dynamic_cast<Barometer&>(base);
        (void)b;
        std::printf("reference conversion caught %s\n", "no");
    } catch (const std::bad_cast&) {
        std::printf("reference conversion caught %s\n", "yes");
    }
    return 0;
}
```

```text
pointer conversion succeeded no
reference conversion caught yes
```

**PS47.** The real object behind `base` is a `Thermometer`, not a `Barometer`.
`dynamic_cast<Barometer*>` notices this at run time and returns `nullptr` — it
does not throw an exception, it just says "not here." The same failure throws
`std::bad_cast` for a reference target; here only the fact that it was caught is
printed, not the text of `what()` — the exact form of the message depends on the
library implementation, which is not what this lesson measures. Since `p` is
`nullptr`, there is no constructed object here; a failed `dynamic_cast` gives
neither a copy nor a part, nothing remains.

#### Removing Constness: const_cast

`const_cast` changes only the constness qualifier of a reference or pointer; the
target type stays the same class, no new object is constructed. The `review`
function below removes constness once to mark an object it received through a
`const` reference:

```cpp
// const-cast.cpp -- does removing constness construct a new object
#include <cstdio>

class Measurer {
public:
    void mark() { marked_ = true; }
    bool marked() const { return marked_; }
private:
    bool marked_ = false;
};

static void review(const Measurer& m) {
    const_cast<Measurer&>(m).mark();
}

int main() {
    Measurer m;
    review(m);
    std::printf("marked %s\n", m.marked() ? "yes" : "no");
    return 0;
}
```

```text
marked yes
```

**PS48.** `const_cast<Measurer&>(m)` gives a reference that views `m` itself,
only with the constness qualifier removed — neither copy nor part, `m`'s
**self**. The condition for this being safe is that `m`'s actual object is
really not defined as `const`; the `m` in `main` is not constant, so the call to
`mark()` does not enter undefined behavior. The same call on an actually `const`
object would be undefined behavior — this lesson neither writes nor runs such a
call.

#### Reinterpreting the Bit Pattern: reinterpret_cast

`reinterpret_cast` is the loosest conversion: no relationship is required
between the target type and the source type, only the same bit pattern is read
as a different type. The only guarantee is that converting back to the same type
yields a value equal to the original — the intermediate value itself carries no
portable meaning, so this lesson does not print it, it only measures the
round-trip equality.

```cpp
// reinterpretation.cpp -- reinterpret_cast round-trip equality
#include <cstdio>
#include <cstdint>

int main() {
    int value = 42;
    int* p = &value;

    std::uintptr_t numeric = reinterpret_cast<std::uintptr_t>(p);
    int* back = reinterpret_cast<int*>(numeric);

    std::printf("round trip equal %s\n", (back == p) ? "yes" : "no");
    return 0;
}
```

```text
round trip equal yes
```

**PS49.** `reinterpret_cast` also does not construct a new object; it reads the
bit pattern carried by `p` first as an integer, then again as a pointer.
`back == p` equality shows that the same address comes back out — but this
guarantee holds only for a round trip that returns to the same type; the number
carried by the intermediate `numeric` value itself is platform-dependent and is
not this lesson's subject.

So which of these four operators does a C-style cast — `(Measurer)t`,
`(Measurer&)t`, and the like — resolve to? The compiler tries them in order:
first `const_cast`, then `static_cast`, then `static_cast` combined with
`const_cast`, and finally `reinterpret_cast`. The first one that makes sense is
chosen — so which operator a C-style cast corresponds to can be inferred by
looking at the relationship between the target type and the source type, but
seeing this while reading is harder than writing `static_cast` or
`dynamic_cast`. This lesson does not use a C-style cast; it names it only to
show which operator it resolves to.

#### The Bounding Measurement

This lesson showed that the **name** of none of the four conversion operators
determines the class — what determines it is the **target type**. The same
`static_cast` refers to the subobject inside `t` (part) when the target is a
reference, and constructs a new object (copy) when the target is a value. This
lesson measured these two separately; guessing the class by looking at the
operator's name was never done in this lesson.

Downcasting an object that is not actually of that type with an incorrect
`static_cast` — for example converting the object behind `base`, which is
actually a `Thermometer`, with `static_cast<Barometer&>` — is undefined
behavior: the compiler does not prevent it, and no check is made at run time
either. This lesson neither wrote nor ran such a call; the path this lesson
shows for safe downcasting is `dynamic_cast`. The platform-dependent
interpretation of the intermediate values `reinterpret_cast` produces, the
undefined behavior of `const_cast` on an actually `const` object, and the
compiler-specific details of a C-style cast's resolution order are also outside
this lesson's scope.

#### Summary

- Converting to a base reference with `static_cast` does not construct a new
  object; it refers to the subobject inside `t` through a narrower type.
- The same `static_cast`, when the target is a value, constructs a new,
  independent object by slicing `t` — same operator, different class.
- `dynamic_cast` gives `nullptr` for a pointer, and `std::bad_cast` for a
  reference, on a failed downcast; in no case does it construct a new object.
- `const_cast` and `reinterpret_cast` also do not construct a new object; they
  open a different access path to the existing object.
- The expression this lesson measures — the base reference obtained with
  `static_cast<const Measurer&>(t)` — is of class **part**: it refers to `t`'s
  own address, through a narrow type.

#### Course Wrap-Up

This lesson was the last lesson of the **C++ Fundamentals and Object Design**
course. Throughout the course, every lesson asked the same question at a
different boundary: which object does an expression work with — itself, a copy
of it, a part of it, or an unnamed temporary?

| Lesson | Measured expression | Which object | Bounding measurement |
| --- | --- | --- | --- |
| Differences Between C and C++ | `struct passed by value` | copy | The call site's class does not say; the decision is in the parameter type |
| Classes and Access Control | `this of the member function` | self | `private` protects the boundary of the class, not the object |
| Constructors and Destructors | `argument constructed from an int` | temporary | The lifetime of a temporary bound to a `const` reference is extended |
| RAII | `member left by the guard` | part | The dangling of a guard holding a reference to a resource was only narrated |
| Copying and Assignment | `deep-copied buffer` | copy | The depth of the copy is read only from the copy constructor's body |
| References | `struct passed by reference` | self | A `const` reference parameter can also bind to a temporary |
| Operator Overloading | `result of a + b` | temporary | In `a + b + c`, only the intermediate result is temporary; the final result is constructed directly in `sum` |
| Inheritance | `function of the base class` | part | Limited to single, non-virtual inheritance |
| Virtual Functions and Vtables | `virtual call from a base reference` | self | Assignment by value and a non-virtual destructor are out of scope |
| Abstract Classes and Interfaces | `call through an interface` | self | Multiple interface inheritance was left to the next lesson |
| Multiple Inheritance and the Diamond Problem | `subobject of the virtual base` | part | The indirection cost of accessing the virtual base was not measured |
| Exceptions | `exception caught by value` | copy | `catch(...)` and throwing inside `noexcept` are out of scope |
| Namespaces and Code Organization | `object referred to by a using declaration` | self | ADL and `#include` mechanics are out of scope |
| Type Conversion Operators | `reference converted to the base` | part | An incorrect `static_cast` downcast was only narrated, not run |

**5 self · 3 copy · 4 part · 2 temporary; 9 existing, 5 new**

Across fourteen lessons the same question was asked at fourteen different
boundaries; the answer was always given by looking at what the compiler
actually constructs, never by the name of the operator or the syntax. The next
course carries this question one step further: when an object gives up the
resource it owns, when it moves a value instead of copying it, and how the
standard library uses this move.

