クラスを継承して機能を受け継ぐ方法を学ぼう

学習の目標

本章では、以下の内容を学習します。

  • クラスの継承の基本概念と使い方を理解する
  • 親クラスの機能を子クラスで再利用する方法を習得する
  • メソッドのオーバーライド(上書き)の仕組みを学ぶ
  • 継承チェーンとメソッド探索の順序を理解する
  • 継承を活用した効率的なプログラミング手法を身につける

はじめに

プログラミングをしていると、似た機能を持つクラスをいくつも作ることがあります。例えば、「犬」と「猫」はどちらも「動物」であり、共通の特徴(名前を持つ、眠る、鳴くなど)を持っています。こうした共通の機能を何度も書くのは非効率ですよね。

そこで役立つのが「継承」という機能です。継承を使うと、あるクラス(親クラス)の機能を別のクラス(子クラス)が受け継ぐことができます。これにより、コードの重複を減らし、効率的にプログラミングできるようになります。

例えば、「動物」という基本クラスを作っておき、そこから「犬」や「猫」といった具体的な動物のクラスを派生させることができます。各動物に共通する機能は「動物」クラスに一度書くだけでよく、各動物の特有の機能だけを個別に定義すればいいのです。

今回は、この継承という概念を使って、コードを整理する方法を学んでいきましょう。

継承の基本

基本的な継承の書き方

まずは継承の基本的な書き方を見ていきましょう。VS Codeでinherit.rbというファイルを作成し、以下のコードを書いてみましょう。

class Animal
def initialize(name)
@name = name
end
def speak
puts "#{@name}が鳴きます"
end
end

このコードでは、動物の基本的な機能を持つAnimalクラスを定義しています。動物の名前を設定するinitializeメソッドと、動物が鳴く様子を表現するspeakメソッドを持っています。

では、このAnimalクラスを継承して、より具体的な動物のクラスを作成してみましょう。

class Dog < Animal
def speak
puts "#{@name}がワンと鳴きます"
end
end
class Cat < Animal
def speak
puts "#{@name}がニャーと鳴きます"
end
end

ここで重要なのは、クラス定義の際に使用している < 記号です。class Dog < Animal という書き方は、「DogクラスはAnimalクラスを継承する」ということを意味しています。これにより、DogクラスはAnimalクラスの機能(メソッドやインスタンス変数)を受け継ぐことができます。

Catクラスについても同様に、Animalクラスを継承しています。

これらのクラスを使って、実際に動物のインスタンスを作り、メソッドを呼び出してみましょう。

dog = Dog.new("ポチ")
cat = Cat.new("タマ")
dog.speak # 「ポチがワンと鳴きます」と表示
cat.speak # 「タマがニャーと鳴きます」と表示

このコードを実行すると、dog.speakでは「ポチがワンと鳴きます」、cat.speakでは「タマがニャーと鳴きます」と表示されます。

ここで注目してほしいのは、DogクラスとCatクラスではinitializeメソッドを定義していないのに、名前を設定できている点です。これは、両クラスがAnimalクラスを継承しているため、Animalクラスのinitializeメソッドが使われているからです。

また、speakメソッドはAnimalクラスでも定義されていますが、DogクラスとCatクラスでは独自のspeakメソッドを定義しています。このように、親クラスで定義されたメソッドを子クラスで上書きすることを「オーバーライド」と呼びます。

継承によって受け継がれるもの

継承を使うと、親クラスのどのような要素が子クラスに受け継がれるのでしょうか? 主に以下のようなものが受け継がれます。

1. インスタンスメソッド

親クラスで定義されたインスタンスメソッドは、子クラスでも使うことができます。上の例では、AnimalクラスのinitializeメソッドがDogクラスとCatクラスに受け継がれています。

2. インスタンス変数

親クラスのメソッド内で設定されたインスタンス変数は、子クラスでも利用できます。上の例では、Animalクラスのinitializeメソッドで設定された@nameというインスタンス変数が、DogクラスとCatクラスのspeakメソッドでも使われています。

3. 定数

親クラスで定義された定数も子クラスで使うことができます。

色々な要素が受け継がれることがわかるかと思います。継承を使うことで、共通のコードを親クラスに書いておき、子クラスではその特有の機能だけを実装することができます。これにより、コードの重複を避け、メンテナンスしやすいプログラムを作ることができます。

継承チェーン

継承は一階層だけでなく、複数の階層にわたって行うこともできます。例えば、「動物」→「犬」→「子犬」というように、連鎖的に継承することも可能です。このような継承の連なりを「継承チェーン」と呼びます。

実際に、継承チェーンの例を見てみましょう。

class Animal
def initialize(name)
@name = name
end
def speak
puts "#{@name}が鳴きます"
end
def sleep
puts "#{@name}が眠ります"
end
end
class Dog < Animal
def speak
puts "#{@name}がワンと鳴きます"
end
end
class Puppy < Dog
def speak
puts "#{@name}が可愛くワンと鳴きます"
end
end

このコードでは、Animalクラスを継承したDogクラス、さらにそのDogクラスを継承したPuppyクラスという継承チェーンを作っています。

実際にPuppyクラスのインスタンスを作って、どのようなメソッドが使えるか確認してみましょう。

puppy = Puppy.new("コロ")
puppy.speak # 「コロが可愛くワンと鳴きます」と表示
puppy.sleep # 「コロが眠ります」と表示

puppy.speakの呼び出しでは、Puppyクラスで定義されたspeakメソッドが実行されます。一方、puppy.sleepの呼び出しでは、PuppyクラスにもDogクラスにもsleepメソッドがないため、Animalクラスのsleepメソッドが実行されます。

このように、メソッドが呼び出されると、まず自分のクラスでそのメソッドを探し、見つからなければ親クラス、さらにその親クラスと遡って探していきます。これを「メソッド探索」と呼びます。

まとめ

この章では、クラスの継承について学びました。以下の内容を理解できたことと思います。

  • 継承を使うことで、既存のクラスの機能を新しいクラスで再利用できる
  • 親クラスのメソッドを子クラスでオーバーライド(上書き)することで、機能を拡張・変更できる
  • 継承チェーンにより、複数階層の継承関係を作ることができる
  • メソッド呼び出し時は、自分のクラスから親クラスへと順にメソッドが探索される
  • 継承は「is-a関係」が成り立つ場合に適している

継承はオブジェクト指向プログラミングの重要な概念の一つです。うまく活用することで、コードの重複を避け、整理された分かりやすいプログラムを作ることができます。しかし、使いすぎるとかえって複雑になることもあるので、クラス間の関係をよく考えて適切に使いましょう。

このセクションは有料サブスクリプションへの登録、またはログインが必要です。完全なコンテンツにアクセスするには、料金ページ(/pricing)をご覧ください。購入済みの場合は、ログインしてください。

Starterプランでより詳しく学習

この先のコンテンツを読むにはStarterプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。

作成者:とまだ
Previous
変わらない値は定数にしよう