#---Inheritance---
Inheritance allows a class to inherit properties and methods from another class. This allows the objects of the inheriting class to gain the functionalities of the parent class, while also having its own unique props and methods.
A dog, a cat and a mouse are all just some animals
with 4 legs and a heart, and can eat, sleep and make
babies just fine.
A bigger dog is still a dog that you can pet.
But a bigger cat is a tiger that will definitely
kill you, and a bigger mouse is a rodent that you will
likely kill.
See the unique features as well as the commonalities?
Inheritance allows you to model this real-world concept.
Use <
to define inheritance between a child class
and a parent class.
class Animal
def initialize(name)
@name = name
end
def speak
"#{@name}: <generic animal sound>"
end
def greet(other_name)
"Welcome #{other_name}. I'm #{@name}."
end
end
The Dog and Cat classes inherit from Animal. Their
objects will get the speak
method from
the parent class for free:
class Dog < Animal
end
class Cat < Animal
end
dog = Dog.new("Pongo")
cat = Cat.new("Jerry")
p dog.speak
p cat.speak
But a dog also wags its tail and a cat purrs. We can add to them their own specific methods:
class Dog < Animal
def wag
"<<wags tail>>"
end
end
class Cat < Animal
def purr
"<<purrs>>"
end
end
(Note tha we’re opening the already-defined child classes and adding methods to them.)
p dog.wag # "<<wags tail>>"
p cat.purr # "<<purrs>>"
p [:speak,:wag].all? { Dog.instance_methods.include?(it) }
## => true
But a generic sounding dog and cat isn’t interesting.
We can make them speak their own tongue by re-defining
the speak
method in the child classes. This
overrides the speak
method in the parent class:
class Dog < Animal
def speak
"#{@name}: Woof!"
end
end
class Cat < Animal
def speak
"#{@name}: Meow!"
end
end
p dog.speak # "Pongo: Woof!"
p cat.speak # "Jerry: Meow!"
super
is how from a child class you’ll call a
method of the same name from the parent class.
We’ll use it in 2 places in our example.
A cat is low-maintenance, but a dog is not. So we might have to take that into account when creating a dog:
class Dog < Animal
def initialize(name, cost)
super(name) # calls Animal's initialize with name
@cost = cost
end
end
## Creating a dog without a cost will now fail.
## Dog.new("Pongo") will fail
p Dog.new("Pongo", 100).speak
The cat has a bigger ego though. So it wants its own
greet
method:
class Cat < Animal
def greet(other_name)
## calls Animal's greet with other_name
## and interpolates the result
"#{super} Jk, I don't care about you."
end
end
p cat.greet("Pongo")
## "Welcome Pongo. I'm Jerry. Jk, I don't care about you."
In both these examples, we used the super
keyword to
call the parent class’s respective methods
(initialize and greet).
Note that super
, when called without any arguments,
calls the parent method with the same arguments that was
passed to the child method. You don’t have to explicitly
list them all.
But if you do want to call the parent
method without passing any arguments, you must call it
like this: super()
. (Only time using () while calling
a method isn’t optional.)
A cat is a cat. But it’s also an animal. (deep)
How do you check that it still has the animalistic
quality in it? You ask it nicely via is_a?
or
kind_of?
:
p cat.class # => Cat
p cat.is_a?(Cat) # => true
p cat.is_a?(Dog) # => false
p cat.is_a?(Animal) # => true
p cat.kind_of?(Animal) # => true
You can just ask a class for its ancestors and it will list out its whole ancestral tree in order:
p Cat.ancestors
## => [Cat, Animal, Object, Kernel, BasicObject]
See Object and BasicObject in the list?
That’s why they say everything is an object in Ruby.