This tutorial provides a comprehensive guide on using inheritance effectively in Ruby. You’ll learn how to define subclasses, use the `super` keyword to call parent class methods, and understand the concept of class hierarchies. By the end, you’ll have a solid grasp of inheritance principles and be able to apply them in real-world scenarios.

Beginner30 minutes

Step 1: Understanding Inheritance Basics

Inheritance allows you to define a class that inherits behavior from another class. The class that inherits is called the subclass or child class, and the class being inherited from is called the superclass or parent class.

To create a subclass, use the < symbol followed by the name of the superclass:

class ChildClass < ParentClass
  # subclass definition
end

The subclass inherits all the methods and attributes from its parent class.

class Animal
  def initialize(name)
    @name = name
  end

  def speak
    "Hello!"
  end
end

class Dog < Animal
end

dog = Dog.new("Buddy")
puts dog.speak  # Output: Hello!

Practice Exercise

Create a Vehicle class with initialize, start_engine, and stop_engine methods. Then, create a Car subclass that inherits from Vehicle and adds a drive method. Instantiate a Car object and call its methods.

Show Solution
class Vehicle
  def initialize(make, model)
    @make = make
    @model = model
  end

  def start_engine
    puts "Engine started."
  end

  def stop_engine
    puts "Engine stopped."
  end
end

class Car < Vehicle
  def drive
    puts "#{@make} #{@model} is driving."
  end
end

car = Car.new("Toyota", "Camry")
car.start_engine  # Output: Engine started.
car.drive         # Output: Toyota Camry is driving.
car.stop_engine   # Output: Engine stopped.
```
In this exercise, we create a `Vehicle` superclass with basic functionality and a `Car` subclass that inherits from `Vehicle` and adds a specific `drive` method. This demonstrates the concept of inheritance and method invocation on a subclass object.

Step 2: Overriding Methods in Subclasses

When a subclass defines a method with the same name as a method in its superclass, it overrides the superclass method. This allows the subclass to provide its own implementation of the method.

To override a method, simply define a method with the same name in the subclass:

class ParentClass
  def greet
    "Hello from ParentClass!"
  end
end

class ChildClass < ParentClass
  def greet
    "Hello from ChildClass!"
  end
end

When the greet method is called on an instance of ChildClass, the overridden version in the subclass will be executed.

class Animal
  def speak
    "Hello!"
  end
end

class Cat < Animal
  def speak
    "Meow!"
  end
end

cat = Cat.new
puts cat.speak  # Output: Meow!

Practice Exercise

Create a Shape class with a calculate_area method that raises a NotImplementedError. Then, create Rectangle and Circle subclasses that override the calculate_area method to provide their respective area calculations. Instantiate objects of each subclass and call the calculate_area method.

Show Solution
class Shape
  def calculate_area
    raise NotImplementedError, "Subclasses must implement the calculate_area method."
  end
end

class Rectangle < Shape
  def initialize(length, width)
    @length = length
    @width = width
  end

  def calculate_area
    @length * @width
  end
end

class Circle < Shape
  def initialize(radius)
    @radius = radius
  end

  def calculate_area
    Math::PI * @radius**2
  end
end

rectangle = Rectangle.new(5, 3)
puts rectangle.calculate_area  # Output: 15

circle = Circle.new(4)
puts circle.calculate_area     # Output: 50.26548245743669
```
In this exercise, we create a `Shape` superclass with an abstract `calculate_area` method that raises a `NotImplementedError`. The `Rectangle` and `Circle` subclasses override the `calculate_area` method to provide their specific area calculations based on their respective attributes. This demonstrates method overriding and polymorphism in action.

Step 3: Using the super Keyword

The super keyword allows a subclass method to call the superclass version of the method. It is commonly used when overriding methods to extend the functionality of the superclass method rather than completely replacing it.

To call the superclass method, use super within the subclass method:

class ParentClass
  def greet
    "Hello from ParentClass!"
  end
end

class ChildClass < ParentClass
  def greet
    super + " and ChildClass!"
  end
end

In this example, the greet method in ChildClass calls super to invoke the greet method from ParentClass and then appends additional text to the result.

class Animal
  def initialize(name)
    @name = name
  end

  def introduce
    "I am an animal."
  end
end

class Dog < Animal
  def introduce
    super + " My name is #{@name}."
  end
end

dog = Dog.new("Buddy")
puts dog.introduce  # Output: I am an animal. My name is Buddy.

Practice Exercise

Create an Employee class with initialize and display_info methods. The initialize method should take name and salary parameters, and the display_info method should print the employee's name and salary. Create a Manager subclass that inherits from Employee and adds a department parameter to initialize and a corresponding display_info method that calls super and appends the department information.

Show Solution
class Employee
  def initialize(name, salary)
    @name = name
    @salary = salary
  end

  def display_info
    "Name: #{@name}, Salary: $#{@salary}"
  end
end

class Manager < Employee
  def initialize(name, salary, department)
    super(name, salary)
    @department = department
  end

  def display_info
    super + ", Department: #{@department}"
  end
end

employee = Employee.new("John Doe", 50000)
puts employee.display_info  # Output: Name: John Doe, Salary: $50000

manager = Manager.new("Jane Smith", 80000, "Sales")
puts manager.display_info   # Output: Name: Jane Smith, Salary: $80000, Department: Sales
```
In this exercise, we create an `Employee` superclass with `initialize` and `display_info` methods. The `Manager` subclass inherits from `Employee` and extends the `initialize` method by calling `super` with `name` and `salary` arguments and adding a `department` parameter. The `display_info` method in `Manager` calls `super` to invoke the superclass method and appends the department information. This demonstrates the usage of `super` to extend superclass functionality in subclasses.

Step 4: Class Hierarchies and Inheritance Chains

Inheritance in Ruby supports class hierarchies, where a subclass can itself serve as a superclass for other classes. This creates an inheritance chain, where methods and attributes are inherited down the hierarchy.

Here's an example of a class hierarchy:

class Animal
  def speak
    "Hello!"
  end
end

class Mammal < Animal
  def feed_young
    "Feeding young..."
  end
end

class Dog < Mammal
  def fetch
    "Fetching..."
  end
end

In this hierarchy, Animal is the superclass of Mammal, and Mammal is the superclass of Dog. The Dog class inherits methods from both Mammal and Animal.

class Animal
  def speak
    "Hello!"
  end
end

class Mammal < Animal
  def feed_young
    "Feeding young..."
  end
end

class Dog < Mammal
  def fetch
    "Fetching..."
  end
end

dog = Dog.new
puts dog.speak       # Output: Hello!
puts dog.feed_young  # Output: Feeding young...
puts dog.fetch       # Output: Fetching...

Practice Exercise

Create a class hierarchy for a library system. Start with a Publication class that has title and publisher attributes and a display_info method. Create a Book subclass that inherits from Publication and adds author and isbn attributes. Create a Magazine subclass that inherits from Publication and adds issue_number and publication_date attributes. Override the display_info method in both subclasses to include the additional attributes.

Show Solution
class Publication
  def initialize(title, publisher)
    @title = title
    @publisher = publisher
  end

  def display_info
    "Title: #{@title}, Publisher: #{@publisher}"
  end
end

class Book < Publication
  def initialize(title, publisher, author, isbn)
    super(title, publisher)
    @author = author
    @isbn = isbn
  end

  def display_info
    super + ", Author: #{@author}, ISBN: #{@isbn}"
  end
end

class Magazine < Publication
  def initialize(title, publisher, issue_number, publication_date)
    super(title, publisher)
    @issue_number = issue_number
    @publication_date = publication_date
  end

  def display_info
    super + ", Issue Number: #{@issue_number}, Publication Date: #{@publication_date}"
  end
end

book = Book.new("Ruby Programming", "ABC Publishers", "John Smith", "978-1234567890")
puts book.display_info
# Output: Title: Ruby Programming, Publisher: ABC Publishers, Author: John Smith, ISBN: 978-1234567890

magazine = Magazine.new("Tech Monthly", "XYZ Media", 42, "May 2023")
puts magazine.display_info
# Output: Title: Tech Monthly, Publisher: XYZ Media, Issue Number: 42, Publication Date: May 2023
```
In this exercise, we create a class hierarchy for a library system. The `Publication` class serves as the superclass, with `Book` and `Magazine` as subclasses. Each subclass adds its specific attributes and overrides the `display_info` method to include the additional information. This demonstrates the concept of class hierarchies and method overriding in a practical scenario.

Step 5: Accessing Superclass Methods with super()

When using super without parentheses, Ruby automatically passes all arguments from the subclass method to the superclass method. However, you can also explicitly pass arguments to the superclass method using super().

Here's an example:

class ParentClass
  def greet(name)
    "Hello, #{name}!"
  end
end

class ChildClass < ParentClass
  def greet(name)
    super(name.upcase)
  end
end

In this case, the greet method in ChildClass calls super(name.upcase), passing the modified name argument to the superclass method.

class Animal
  def make_sound(sound)
    "#{sound}!"
  end
end

class Cat < Animal
  def make_sound(sound)
    super("Meow")
  end
end

cat = Cat.new
puts cat.make_sound("Purr")  # Output: Meow!

Practice Exercise

Create a Person class with an initialize method that takes name and age parameters and a display_info method that prints the person's name and age. Create a Student subclass that inherits from Person and adds a grade parameter to initialize. Override the display_info method in Student to call the superclass method using super() and append the grade information.

Show Solution
class Person
  def initialize(name, age)
    @name = name
    @age = age
  end

  def display_info
    "Name: #{@name}, Age: #{@age}"
  end
end

class Student < Person
  def initialize(name, age, grade)
    super(name, age)
    @grade = grade
  end

  def display_info
    super() + ", Grade: #{@grade}"
  end
end

person = Person.new("John Doe", 30)
puts person.display_info  # Output: Name: John Doe, Age: 30

student = Student.new("Jane Smith", 18, 12)
puts student.display_info  # Output: Name: Jane Smith, Age: 18, Grade: 12
```
In this exercise, we create a `Person` class with `initialize` and `display_info` methods. The `Student` subclass inherits from `Person` and adds a `grade` parameter to `initialize`. In the `Student` class, the `display_info` method calls `super()` to invoke the superclass method and appends the grade information. This demonstrates the usage of `super()` to pass arguments explicitly to the superclass method.

Sign in to take Cornell notes on this lesson — they save automatically and stay with your account.

Sign in

Click to access the login or register cheese