C# for Unity — Lesson #6: Inheritance and Interfaces
April 12 2021
What are Interfaces
Interfaces are a set of methods, properties, and other members that a target class must implement.
C# is a type-safe language, meaning it checks if every statement is using Data Types correctly, by using an interface as your Data Type, you are able to access the interface fields on different classes.
Build an Interface
The interface declaration is pretty similar to a class declaration:
The idea is to have multiple classes that implement the IDamageable class, so we can reference the Interface rather than the classes themselves. In this example, we could have the Player, Enemies, and Props all implement the IDamegeable, this way if we get a collision in Unity, we check if it is IDamegeable, and apply corresponding damage, regardless of its class.
The main differences between classes and interfaces are:
- Interfaces can't declare variable fields or constructors.
- Interface members don't have access modifiers, as they are all public.
- Interfaces don't declare methods or properties implementations, only their declarations. Each class that implements the interface will have its own methods or properties body.
It is a good practice to always name an interface with a starting 'I'.
Implementing an Interface
To use an interface we need first to declare that a class implements the interface, and then implement each member of that interface.
- During the class declaration, after the class name, add a colon ':' followed by the interface name.
- The class must then implement every member declared in the interface, making them all public.
If you forget to implement a member of the interface, you will get a compilation error in the unity console similar to this: error CS0535: 'Enemy' does not implement interface member 'IDamageable.ApplyDamage(int)'.
Multiple classes implementing an Interface
Like I said before, interfaces really shine when there are multiple classes implementing it, that's when we can treat the classes that implement them as a single type.
Tip: "CurrentHealth => isBroken ? 0 : 1;" is a shorthand for declaring a getter body. This is called a lambda expression in case you want to dig deeper.
Inheritance is like an interface on steroids, while interfaces are thought of as what a class DOES, inheritance is what a class IS. Inheritance will not only give you the actions that each class that inherits from it has, but also some or all implementations of said members, with a bonus of being able to declare fields and constructors.
Oh wow! So why don't we just use inheritance you ask.
First, there is a hard condition, we can only inherit from a single class, but can implement multiple interfaces. But also, from a design perspective, they are different, again: interfaces are what a class does, the other what a class IS.
In inheritance, one class inherits the members of another class, so to help with communication, the inherited class is called the Super Class or Base Class, while the one that inherits is the Subclass or Derived Class.
Inheritance is great to tackle the constant problem of code reuse, by having the shared implementations in the base class, if we ever need to change that code, we only need to change it in a single place.
Inheritance uses only things we are already familiar with, declare the base class as you would any other class, and as for the derived class declare that it inherits from the base class as you would declare it implements an interface.
In this example, the new class Orc has 3 public members:
- Shout, implemented by the derived class Orc
- CurrentHealth and ApplyDamage, inherited from the base class Enemy
- A class can inherit from a single class and implement multiple interfaces, during declaration the interfaces must be declared after the base class inheritance.
- A base class can in turn inherit from another class, this way inheritance becomes like a tree.
Protected Access Modifier
As a reminder, public members can be accessed from anywhere, while private members can only be accessed by the same class that declared them. But what if I wanted to access a base class field, but still keep it blocked to others?
Yes, the protected access modifiers, who would have guessed. Just use it like you would any other access modifier 😉
Override Inherited Members
So, what if we wanted to make that ApplyDamage work a bit differently on orcs, or even completely different? That is why we have overrides.
When you want to extend the logic of a base class method, add an extra 'virtual' modifier to the method declaration, telling the compiler that this method may have additional logic added during inheritance.
The derived class must then add an 'override' while declaring that same function, and then declare the method as you would normally.
If you want to reuse the base class functionality, you can explicitly call its function by calling "base.NameOfTheOverridenMethod".
Abstract members work similarly to interface members, you declare an abstract member and give it no implementation, this way any derived class must have its own implementation of said member.
Since the base class has unimplemented members, we can't instantiate them, only their derived classes, so we must also tag the class as abstract.
Coming up next!
Next week is our last and long-awaited chapter: Integrating into Unity. Now that we got the tools, it's time for some hands-on coding, let's see how it all ties together and create a cool game while we are at it!
Happy coding 🙂