C# > Object-Oriented Programming (OOP) > Inheritance > Base and Derived Classes

Basic Inheritance Example: Animal and Dog

This example demonstrates basic inheritance in C#. We define a base class `Animal` with common properties and methods. Then, we create a derived class `Dog` that inherits from `Animal` and adds its own specific properties and behaviors. This illustrates how inheritance promotes code reuse and allows you to model 'is-a' relationships.

Defining the Base Class: Animal

The `Animal` class serves as the base class. It includes properties like `Name` and `Color`, and methods like `MakeSound` and `GetDescription`. The `virtual` keyword in `MakeSound` and `GetDescription` allows derived classes to override these methods and provide their own implementations. The constructor initializes the `Name` and `Color` properties.

public class Animal
{
    public string Name { get; set; }
    public string Color { get; set; }

    public Animal(string name, string color)
    {
        Name = name;
        Color = color;
    }

    public virtual string MakeSound()
    {
        return "Generic animal sound";
    }

    public virtual string GetDescription()
    {
        return $"This is a {Color} animal named {Name}.";
    }
}

Defining the Derived Class: Dog

The `Dog` class inherits from the `Animal` class using the `:` syntax. It adds a specific property, `Breed`, which is relevant only to dogs. The constructor calls the base class constructor using `base(name, color)` to initialize the inherited properties. The `override` keyword indicates that the `MakeSound` and `GetDescription` methods are overriding the base class implementations. Finally, a new method `Fetch` specific to the `Dog` class has been added.

public class Dog : Animal
{
    public string Breed { get; set; }

    public Dog(string name, string color, string breed) : base(name, color)
    {
        Breed = breed;
    }

    public override string MakeSound()
    {
        return "Woof!";
    }

    public override string GetDescription()
    {
         return $"This is a {Color} {Breed} named {Name}.";
    }

    public string Fetch(string item)
    {
        return $"{Name} is fetching {item}!";
    }
}

Using the Classes

This code demonstrates how to create instances of the `Animal` and `Dog` classes and access their properties and methods. Notice how the `Dog` instance's `MakeSound` and `GetDescription` methods behave differently from the `Animal` instance's, due to overriding. The `Fetch` method is unique to the `Dog` class.

Animal animal = new Animal("Generic", "Brown");
Console.WriteLine(animal.GetDescription()); // Output: This is a Brown animal named Generic.
Console.WriteLine(animal.MakeSound()); // Output: Generic animal sound

Dog dog = new Dog("Buddy", "Golden", "Retriever");
Console.WriteLine(dog.GetDescription()); // Output: This is a Golden Retriever named Buddy.
Console.WriteLine(dog.MakeSound()); // Output: Woof!
Console.WriteLine(dog.Fetch("the ball")); // Output: Buddy is fetching the ball!

Concepts Behind the Snippet

This snippet illustrates the core principles of inheritance:

  • Code Reusability: The `Dog` class inherits properties and methods from the `Animal` class, avoiding code duplication.
  • Extensibility: The `Dog` class extends the functionality of the `Animal` class by adding new properties and methods.
  • Polymorphism: The `MakeSound` method behaves differently depending on whether it's called on an `Animal` or a `Dog` object.

Real-Life Use Case

Consider a system for managing different types of vehicles. You could have a base class `Vehicle` with properties like `NumberOfWheels` and `EngineType`. Then, you could have derived classes like `Car`, `Truck`, and `Motorcycle`, each inheriting from `Vehicle` and adding their own specific properties and behaviors. For example, `Car` might have a property `NumberOfDoors` and a method `OpenTrunk`. This structure simplifies the design and maintenance of the system.

Best Practices

  • Use inheritance judiciously. Overuse can lead to complex and brittle class hierarchies.
  • Favor composition over inheritance when appropriate. Composition involves creating objects by combining other objects, which can provide more flexibility.
  • Adhere to the Liskov Substitution Principle. This principle states that derived classes should be substitutable for their base classes without altering the correctness of the program.

Interview Tip

Be prepared to explain the difference between inheritance and composition. Also, understand the benefits and drawbacks of each approach. A common interview question is to design a class hierarchy for a real-world scenario, such as vehicles or employees.

When to Use Inheritance

Use inheritance when you have a clear 'is-a' relationship between classes. For example, a `Dog` 'is-a' `Animal`. Inheritance is suitable when you want to reuse code and extend the functionality of an existing class.

Memory Footprint

Derived classes typically have a larger memory footprint than their base classes because they contain the members of the base class plus their own unique members. However, the memory overhead is usually negligible unless you have a very large number of objects.

Alternatives

  • Composition: As mentioned before, composition is an alternative to inheritance. Instead of inheriting from a base class, a class can contain instances of other classes.
  • Interfaces: Interfaces define a contract that classes can implement. They provide a way to achieve polymorphism without inheritance.

Pros

  • Code Reusability: Avoids code duplication.
  • Extensibility: Allows you to extend the functionality of existing classes.
  • Polymorphism: Enables you to treat objects of different classes in a uniform way.

Cons

  • Tight Coupling: Can create tight coupling between classes, making it difficult to modify the base class without affecting derived classes.
  • Fragile Base Class Problem: Changes to the base class can have unintended consequences in derived classes.
  • Overuse can lead to complex and brittle class hierarchies.

FAQ

  • What is the difference between `virtual` and `override`?

    The `virtual` keyword is used in the base class to indicate that a method can be overridden by derived classes. The `override` keyword is used in the derived class to provide a new implementation of a `virtual` method from the base class.
  • What is the purpose of the `base` keyword?

    The `base` keyword is used to access members of the base class from within the derived class. It is commonly used to call the base class constructor or to access overridden methods.
  • Can a class inherit from multiple base classes in C#?

    No, C# does not support multiple inheritance of classes. However, a class can implement multiple interfaces.