> For the complete documentation index, see [llms.txt](https://lauradang.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lauradang.gitbook.io/notes/c++/cs_246/lecture-15.md).

# Lecture 15

**Consider the following:** When is a book heavy?

* ordinary books: >200 pages
* textbooks: >500 pages
* comicbooks: >30 pages

```
class Book {
  ...
  protected:
    int length;
  public:
    bool isHeavy() const {
      return length > 200;
    }
};

class Text: public Book {
  ...
  public:
    bool isHeavy() const {
      return length > 500;
    }
};

class Comic: public Book {
  ...
  public:
    bool isHeavy() const {
      return length > 30;
    }
};

// client:
Book b {"small", 50};
Comic c {"Big", 80, "Lushman"};
Book b = Comic{"Big", 80, "Lushman"};
b.isHeavy(); // **What does this return?
```

\*\*It returns false since Book::isHeavy() runs

**Why does `Book::isHeavy()` run?**

```
Book b = Comic {...};
```

* Tries to fit a comic object in b while there's only space for a Book object
* Comic is **sliced** (i.e. the hero field is chopped off)
* The Comic is a Book now!

```
Comic {__, 40, __};
Book *pb = &c;
Book *pc = &c;
```

* When accessing objects through pointers, slicing is unnecessary (so it won't happen)

```
pc->isHeavy(); // runs Comic::isHeavy()
pb->isHeavy(); // runs Book::isHeavy()
```

**How does compiler decide which method to run?**

* Uses the **type of the pointer or reference** to decide which isHeavy to run. **(it does not consider the type of the actual object)**
* So a comic is only a comic if you point to it by a comic pointer or reference

**How can we make Comic act like a comic even when pointed to by a Book pointer?**

**Solution**: Declare the method virtual!

## Virtual Methods/Dynamic Dispatch

#### Dynamic Dispatch:

* Type of the object is considered at runtime, rather than from the type of the variable i.e. Choose which class method to run based on the actual type of the object at run time
* To get dynamic dispatch, you need **virtual methods**

```
virtual bool Book::isHeavy() const;
Bool Comic::isHeavy() const override;

// Now:
Comic {__, 40, __};
Comic *pc = &c;
Book *pb = &c;
Book &rb = c;

pc->isHeavy(); // runs Comic::isHeavy()
pb->isHeavy(); // runs Comic::isHeavy()
rb.isHeavy(); // runs Comic::isHeavy()
Book b = c; // runs Book::isHeavy(), you can't stop slicing even if it's virtual!
```

## Polymorphism

* Accomodating multiple types under one abstraction
* Dynamic dispatch allows us to do this

**Example of polymorphic code:**

```
Book *myBooks[20];
...
for (int i=0; i < 20; ++i) {
  cout << myBooks[i]->isHeavy();
}
```

**Remark**: This is why we can pass an ifstream to a function

```
void f(istream &in);
```

* ifstream is a subclass of istream

***DANGER***:

```
class One {
  int n, y;
}

class Two: public One {
  int z;
}

void f(one *n) {
  a[0] = {6,7};
  a[1] = {6,9};
}

Two myArray[2] = {{1,2,3},{4,5,6}};
f(myArray);

// myArray: 1 2 3 | 4 5 6
// a[0] = {6,7}: 6 7 3 | 4 5 6
// a[1] = {8, 9}: 6 7 8 | 9 5 6
// wanted: 6 7 3 | 8 9 6
// compilier thinks it has an order of one's not two's!, therefore misaligned
```

**The Point**: Never use an array of objects polymorphically

## Destructors (Polymorphism)

```
class X {
  int *x;
  public:
    x(int n): n{new int[n]}} {};
    ~x() {
      delete [] n;
    }
};

class Y: public X {
  int *y;
  public:
    Y(int n, int m): X{n}, y{new int[m]}} {}
    ~Y() {
      delete [] y;
    }
};

// Y's destructor calls X's destructor!
```

**What happens when an object is destroyed?**

1. Destructor body runs
2. Fields are destructed in reverse dealing order
3. Superclass part is destructed (it's destructor called)
4. space is deallocated

Consider:

```
X *myX = new Y{10, 20};
delete myX; // **This leaks, but why?
```

\*\* This calls X's destructor only (since the type of the pointer was X\*), Fix this by making X's destructor virtual

**The Point**: Always make the destructor virtual in classes that have subclasses, even if the destructor does not do anything!

* Otherwise when we have a polymorphic variable with the type of the base class, it will not call the destructors of the subclasses

## Final

If a class is not meant to have subclasses, declare it `final`.

```
// Now you cannot make subclasses of Y
class Y final: public X {
  ...
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lauradang.gitbook.io/notes/c++/cs_246/lecture-15.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
