| Keywords | :, virtual, override, abstract, base, sealed, interface |
|---|---|
| Category | Object-oriented programming |
| In Unity | class Player : MonoBehaviour, IPointerClickHandler |
Inheritance & Interfaces
Inheritance lets a class build on another class and reuse its code. Player : MonoBehaviour means "a Player is a MonoBehaviour, plus some extras". Interfaces describe what a class can do, without saying how.
Inheritance is a family tree: a Goblin is an Enemy, which is a MonoBehaviour. The Goblin inherits everything the Enemy has, like eye color from a parent. An interface is a skill certificate, such as a driving licence. A Goblin, a Crate and a Wall aren't related, but each can hold the "can take damage" certificate. Code that needs a driver just asks for the licence, not the family name.
Inheritance basics
using UnityEngine;
// Base class: shared by every enemy
public class Enemy : MonoBehaviour
{
[SerializeField] protected float health = 50f; // protected: children can use it
public void TakeDamage(float amount)
{
health -= amount;
if (health <= 0f) Die();
}
// virtual: children MAY replace this
protected virtual void Die()
{
Destroy(gameObject);
}
}
// Child class: everything Enemy has, plus changes
public class ExplodingSlime : Enemy
{
[SerializeField] private GameObject explosionPrefab;
// override: replace the parent's version
protected override void Die()
{
Instantiate(explosionPrefab, transform.position, Quaternion.identity);
base.Die(); // also run the parent's version (Destroy)
}
}
| Keyword | Meaning |
|---|---|
class B : A | B inherits from A. A class can only have one parent class. |
virtual | "Children are allowed to override this." |
override | "I'm replacing my parent's virtual/abstract version." |
base.Method() | Call the parent's version from inside the override. |
abstract | On a class: can't be used directly, only inherited. On a method: no body; children must override it. |
sealed | Nobody can inherit from this class (or override this method further). |
Abstract classes
public abstract class Weapon : MonoBehaviour
{
[SerializeField] protected float cooldown = 0.5f;
private float nextUse;
public void TryUse()
{
if (Time.time < nextUse) return;
nextUse = Time.time + cooldown;
Use(); // each weapon decides what "use" means
}
protected abstract void Use(); // no body: every weapon MUST write one
}
public class Sword : Weapon
{
protected override void Use() { Debug.Log("Swing!"); }
}
public class Bow : Weapon
{
protected override void Use() { Debug.Log("Shoot arrow!"); }
}
// The player doesn't care which weapon it has:
[SerializeField] private Weapon equipped; // drag a Sword OR a Bow here
void Update() { if (Input.GetButtonDown("Fire1")) equipped.TryUse(); }
You can't add an abstract class like Weapon to a GameObject by itself, only its concrete children.
Interfaces
public interface IDamageable
{
void TakeDamage(float amount);
}
public interface IInteractable
{
string Prompt { get; } // interfaces can require properties too
void Interact(GameObject who);
}
// A class can have ONE parent class but MANY interfaces
public class Barrel : MonoBehaviour, IDamageable, IInteractable
{
public string Prompt => "Kick barrel";
public void TakeDamage(float amount) { /* explode */ }
public void Interact(GameObject who) { /* roll away */ }
}
// Using them: ask for the ability, not the class
void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent(out IDamageable d)) d.TakeDamage(10f);
}
Unity uses interfaces itself: implement IPointerClickHandler on a UI object and Unity calls your OnPointerClick method.
IDamageable, so a sword that asks for IDamageable works on every one of them.Abstract class or interface?
| Abstract class | Interface | |
|---|---|---|
| Shares code? | Yes, fields and method bodies | Mostly no, just the "contract" |
| How many per class? | One | As many as you want |
| Relationship | "is a" (a Bow is a Weapon) | "can do" (a Barrel can be damaged) |
| Shows in Inspector fields? | Yes ([SerializeField] Weapon w) | No, not directly ([SerializeField] IDamageable d won't show) |
What happens at runtime
- A child object contains all the fields of its parent classes. An
ExplodingSlimehashealtheven though it doesn't declare it. - When you call a
virtualmethod, C# checks the object's real type at runtime and runs the most-derived override.enemy.TakeDamage()on a slime calls the slime'sDie(), even thoughTakeDamageis written inEnemy. - Unity's messages (
Update,Start) are also inherited. If the parent has a privateUpdateand the child declares its own, only the child's runs (the parent's is hidden, not combined). Make itprotected virtualand callbase.Update()to run both.
Common Mistakes
- Deep inheritance trees (Entity → Character → Enemy → Melee → Goblin → ArmoredGoblin). Hard to change. Prefer small components and interfaces; see "composition" in Better Ways to Do Things.
- Forgetting
override. Writingvoid Die()in the child withoutoverridehides the parent's method instead of replacing it (warning CS0114). Calls through anEnemyvariable still run the parent's version. - Two
Startmethods fighting. See the runtime note above.
See also
- Types & Type Checking (
is,as, casting to a child class) - Generics
This page is a simplified, AI-assisted interpretation. For the complete and authoritative reference, see the official Microsoft C# documentation.