> For the complete documentation index, see [llms.txt](https://notes.danfitz.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://notes.danfitz.com/csharp/csharpintermediate/3-inheritance.md).

# Inheritance

## Access Modifiers

One of the core ideas that OOP tries to promote is to make your classes into **black boxes**. That's because if you expose the implementation details of a class, other code that uses that class will be affected if you *change* those implementation details.

In contrast, everything we *want* to make accessible is part of the **public interface** of a class: it's what we want to expose to our users.

To create the black box and public interface of a class, we have **access modifiers**. If you recall, these are the ones we have available in C#:

* `public`
* `private`
* `protected`
* `internal`
* `protected internal`

### `public`

Makes a field/property/method **accessible everywhere**. You use `public` when you want your field/property/method to be part of the public interface of the class.

```cs
public class Customer
{
  public void Promote() {}
}

var customer = new Customer();
customer.Promote();
```

### `private`

Makes a field/property/method **only accessible inside the class**. You use `private` when you're dealing with the implementation details and so don't want to give open access.

```cs
public class Customer
{
  private int CalculateRating() {}

  public void Promote()
  {
    // Implementation details!
    if (CalculateRating() > 100)
    {
       // Do something...
    }
  }
}

var customer = new Customer();
customer.CalculateRating(); // fails
```

### `protected`

Makes a field/property/method **accessible from the class AND its derived classes**.

```cs
public class Customer
{
  public int CalculateRating() {}
}

public class VIP : Customer
{
  public void Promote()
  {
    // Access to implementation details!
    if (CalculateRating() > 1000)
    {
      // Do something...
    }
  }
}
```

**Pro tip**: `protected` is not good practice because it's not enough of a black box. Any derived classes still are granted access! For that reason, `private` is preferred over `protected`.

### `internal`

Makes a class itself **accessible only from the same assembly**. You use `internal` when a class you create is a useful implementation detail for all the classes in its assembly.

```cs
internal class RateCalculator {}

// In the same assembly: WORKS
var calc = new RateCalculator();

// In another assembly: FAILS
var calc = new RateCalculator();
```

### `protected internal`

Makes a field/property/method **accessible from the same assembly** OR **accessible from any derived classes**.

```cs
public class Customer
{
  protected internal void Weirdo() {}
}

// In another assembly: WORKS
var customer = new Customer();
customer.Weirdo();

// In a derived class: WORKS
public class VIP : Customer {}
var vip = new VIP();
vip.Weirdo();
```

**Pro tip**: This access modifier is really weird. You likely won't use it.

## Constructors and Inheritance

Suppose you create a `Vehicle` class and a derived `Car` class that inherits from `Vehicle`. There are 2 things to note about the `Vehicle` constructor:

1. Base class constructor is always executed *before* the derived class constructor.
2. Base class constructor is *never inherited* by the derived class.

In code, that means you have to explicitly create a new constructor for the derived class:

```cs
public class Vehicle
{
  private string _registrationNumber;

  public Vehicle(string registrationNumber)
  {
    _registrationNumber = registrationNumber;
    Console.WriteLine("Vehicle gets initialized first");
  }
}

public class Car : Vehicle
{
  public Car(string registrationNumber)
  {
    _registrationNumber = registrationNumber;
    Console.WriteLine("Car gets initialized second");
  }
}
```

There's 2 troubles with this though!

1. You can't initialize `_registrationNumber` in the `Car` constructor because it's a `private` field. This means it's not accessible in a derived class like `Car`.
2. The constructor for `Car` feels like repeated code. Is there a way to simplify this?

To solve this, we introduce the `base` keyword: it passes arguments to the base class constructor while *inside* the derived class.

```cs
public class Car : Vehicle
{
  public Car(string registrationNumber)
    : base(_registrationNumber)
  {
    // Initialize fields *specific* to the Car class here
    Console.WriteLine("Car gets initialized second");
  }
}
```

### Upcasting and Downcasting

**Upcasting** is converting a derived class to a base class, and **downcasting** is converting a base class to a derived class.

### Upcasting

Suppose you have a base class and derived class. To upcast, i.e., convert a derived class *to* its base class, C# does it using **implicit type conversion**.

```cs
public class Shape {}
public class Circle : Shape {}

Circle circle = new Circle();
Shape shape = circle; // upcasting
```

**Note**:

* `shape` and `circle` are actually the same object in memory (`shape == circle` returns `true`), but they have different views.
* `circle` can see all the `Circle` members *and* the `Shape` members.
* In contrast, `shape` can only see the `Shape` members.
* You'll see later how this is useful when we talk about polymorphism.

**Pro tip**: One common use case for upcasting is when you pass arguments to a function and/or constructor. When a parameter supports a base class, you know you can also *pass the derived class*, and it will be implicitly converted!

```cs
public class ImplicitCast
{
  private Shape _shape;
  public ImplicitCase(Shape shape)
  {
    _shape = shape;
  }
}

var obj = new ImplicitCast(new Circle());
```

### Downcasting

With downcasting, you must perform **explicit type conversion**, which is known as casting.

```cs
public class Shape {}
public class Circle : Shape {}

Shape shape = new Shape();
Circle circle = (Circle)shape; // downcasting
```

**Pro tip**: A common use case for downcasting is when you need access to a greater view of available fields/properties/methods. For example, maybe you have a generic `object`, but you believe it is a `Button`, and you want to use the `Button` members.

```cs
private void ButtonClick(object sender)
{
  sender.clickDetails; // not accessible
  var button = (Button) sender;
  button.clickDetails; // accessible
}
```

### The `as` keyword

When downcasting, you can't always guarantee it will work. That means there may be an `InvalidCastException` error, breaking the application if it's not handled.

To more elegantly solve this without creating an error, you use the `as` keyword:

```cs
Car car = (Car)shape; // throws error

Car car = shape as Car; // returns null if fails
if (car != null)
{
  // Do something...
}
```

### The `is` keyword

Alternatively, instead of `as` where you cast first and then find out if it failed, you can use `is` to check if it's possible to cast.

```cs
if (shape is Car)
{
  Car car = (Car)shape;
}
```

## Boxing and Unboxing

If you recall, there are value types and reference types.

Value types:

* Stored in stack where items in memory get removed immediately after they go out of scope.
* Stack also has more limited amount of memory.
* Examples: `int`, `bool`, `char`

Reference types:

* Stored in heap where items require a longer lifetime.
* Heap also has a lot more memory allocation.
* Examples: any classes like objects, arrays, strings

Additionally, we also know that `object` is the base class of *all* classes.

```cs
object obj = new Shape();
```

### Boxing

What happens if we implicitly convert a value type into an `object`? This is known as **boxing**:

```cs
object obj = 10;
```

Behind the scenes, the CLR boxes the value `10` and stores it in the *heap*. Then it places a reference to that object in the *stack*.

**Note**: Creating an object has a performance cost, so be aware of this.

### Unboxing

**Unboxing** is exactly what you think: after a value type has been boxed in a reference in the heap, you can extract the value and put it back in the stack by *casting* the reference.

```cs
object obj = 10;
int number = (int)obj;
```
