E: Inheritance & polymorphism¶
Concepts in Action¶
Suppose you’re working on a game where each GameObject represents a character, such as a player or an enemy. Each character might have common components like a CharacterController
for basic movement, a Health
component for tracking health points, and a SpriteRenderer
for displaying the character’s sprite.
However, each character might also have unique components. For instance, the player GameObject might have a PlayerController
component for handling user input, while an enemy GameObject might have an EnemyAI
component for defining its AI behavior.
You can leverage inheritance
by designing a base class (e.g., Character) with common functionality and then creating subclasses (like Player and Enemy) that inherit from this base class and add or override specific behaviors.
With polymorphism
, you can treat Player and Enemy objects as Character objects. This becomes particularly useful when you want to write code that operates on all characters, regardless of their specific types. For example, you might have a Damage function in your Character class that gets called when a character gets hit. Depending on the actual class of the character (Player, Enemy, etc.), the correct Damage function will get called.
These principles will help you better structure your Unity projects, leading to code that’s easier to read, maintain, and extend. Moreover, they can make your work in Unity more efficient and enjoyable, as you can spend more time on the fun parts of game development and less time on tedious tasks like duplicating code.
Introduction¶
Imagine you’re running a pet shop with different kinds of pets: dogs, cats, birds, and so on. Now, all these pets are different species but they share some common characteristics. They all eat, sleep, and move, though they may do so in different ways. So, in the context of our programming pet shop, we might create a base class called Animal. This Animal class may define methods for eating, sleeping, and moving.
Now, let’s consider a Dog class. A dog is a specific kind of animal, so it makes sense for our Dog class to inherit from the Animal class. That way, it automatically gets the eating, sleeping, and moving behaviors. But dogs have some behaviors that not all animals share. For instance, dogs can bark. So, in the Dog class, we can add a method specifically for barking.
Continuing with this analogy, Bird is another class that can inherit from Animal. Birds also eat, sleep, and move, but they do so in a different way. Birds can also fly, which not all animals can do. So, in the Bird class, we can override the Move method to reflect how birds move (i.e., by flying), and we can add a Fly method specifically for flying.
This is an example of polymorphism. Even though Dog and Bird are different classes, they’re both types of Animal. That means you can create a list of Animal objects and put Dog and Bird objects in it. When you go through that list and call the Move method on an Animal object, it’ll do the right thing depending on whether it’s a Dog or a Bird.
This way, you can handle different specific cases (like dogs and birds) with more general code (like handling animals), making your code more flexible and easier to manage.
Prior C# knowledge required¶
Before diving into this topic, you should understand the basics of C# programming, including variables, types, and classes. It would be best if you also had a basic understanding of Object-Oriented Programming (OOP).
Definition¶
Inheritance and polymorphism are fundamental principles of object-oriented programming that enable code reuse and flexibility.
Inheritance is a mechanism where you can create a new class using an existing class. The new class, known as the subclass, inherits the members (fields, properties, and methods) of the existing class, referred to as the baseclass. This means you can reuse the code from the baseclass in the subclass, and you can also add new members or override the inherited ones in the subclass to tailor its behavior. Inheritance represents an “is-a” relationship. For example, a Dog is an Animal, so it makes sense for Dog to inherit from Animal.
Polymorphism, on the other hand, allows you to treat objects of a subclass as if they were objects of their baseclass, while still invoking the correct subclass methods. This means you can write general code that works with baseclass references, but behaves differently depending on the actual class of the object being referenced. For example, you might have a Speak method in your Animal class and overridden versions of this method in your Dog and Cat classes. With polymorphism, calling Speak on an Animal reference will invoke the correct method depending on whether the actual object is a Dog or a Cat.
Together, inheritance and polymorphism help you create more modular and maintainable code, as you can define common behaviors in baseclasses and specific behaviors in subclasses, and you can write code that works with baseclass references while still taking advantage of subclass-specific behaviors.
Differences to JavaScript¶
-
Inheritance: In C#, inheritance is achieved using a simple : operator. For instance,
public class Dog : Animal
signifies that Dog is a subclass of Animal. In JavaScript ES6, the extends keyword is used for inheritance (class Dog extends Animal). -
Polymorphism: In C#, polymorphism is strongly supported due to the statically typed nature of the language. You can have a method in a base class that can be overridden by a derived class, and the decision of which method to call is made at runtime based on the actual type of the object. In JavaScript, polymorphism can be achieved, but it works differently due to the dynamic nature of the language. JavaScript’s prototype-based inheritance and the flexibility of functions as first-class objects provide a different approach to achieving polymorphism.
Similarities to JavaScript¶
-
Inheritance: Both C# and JavaScript ES6 support the concept of inheritance, allowing for code reuse and a hierarchical object structure.
-
Polymorphism: Both languages support polymorphism, allowing for flexible code that can handle different object types with a common interface.
Examples¶
public class Animal
{
public virtual void Speak()
{
Debug.Log("The animal makes a sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Debug.Log("The dog barks");
}
}
public class Bird : Animal
{
public override void Speak()
{
Debug.Log("The bird sings");
}
}
public class Program
{
void CreateAnimals()
{
Animal[] animals = new Animal[2]
{ new Dog(), new Bird() };
for (int i = 0; i < animals.Length; i++)
{
animals[i].Speak(); //each
}
}
}
Key Takeaways¶
Inheritance allows classes to inherit fields and methods from another class: Just like how children inherit characteristics from their biological parents, classes in C# can inherit properties and methods from a parent class. This is a powerful feature that allows you to write code that’s easier to understand and maintain.
Inheritance promotes code reuse and organization: By using inheritance, you can create a base class that defines common properties and methods, and then create derived classes that inherit these. This allows you to reuse code, making your programs more efficient and easier to maintain.
Polymorphism allows objects to take on many forms: The real power of inheritance comes from polymorphism, the ability of objects to take on many forms. In our example, we created an array of Animal objects but populated it with Dog and Bird objects. Despite this, we were still able to call the Speak method on each object in the array, even though the actual method being called depends on the type of the object.
Polymorphism in C# is implemented using virtual and override keywords: The virtual keyword is used to modify a method, property, indexer, or event in a base class and allow it to be overridden in derived classes. The override keyword is used to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.
Understanding these concepts is crucial for writing efficient and effective C# code: These are fundamental concepts in C#, and understanding them will help you write code that is more efficient, easier to maintain, and more robust. It also opens up more advanced concepts and techniques, like interfaces and abstract classes.
Further Reading¶
- Microsoft: Inheritance
- Microsoft: Polymorphism
- Pluralsight course - OOP in C#
- C# Programming Yellow Book