クラスを継承して機能を受け継ぐ方法を学ぼう
学習の目標
本章では、以下の内容を学習します。
- クラスの継承の基本概念と使い方を理解する
- 親クラスの機能を子クラスで再利用する方法を習得する
- メソッドのオーバーライド(上書き)の仕組みを学ぶ
- 継承チェーンとメソッド探索の順序を理解する
- 継承を活用した効率的なプログラミング手法を身につける
はじめに
プログラミングをしていると、似た機能を持つクラスをいくつも作ることがあります。例えば、「犬」と「猫」はどちらも「動物」であり、共通の特徴(名前を持つ、眠る、鳴くなど)を持っています。こうした共通の機能を何度も書くのは非効率ですよね。
そこで役立つのが「継承」という機能です。継承を使うと、あるクラス(親クラス)の機能を別のクラス(子クラス)が受け継ぐことができます。これにより、コードの重複を減らし、効率的にプログラミングできるようになります。
例えば、「動物」という基本クラスを作っておき、そこから「犬」や「猫」といった具体的な動物のクラスを派生させることができます。各動物に共通する機能は「動物」クラスに一度書くだけでよく、各動物の特有の機能だけを個別に定義すればいいのです。
今回は、この継承という概念を使って、コードを整理する方法を学んでいきましょう。
継承の基本
基本的な継承の書き方
まずは継承の基本的な書き方を見ていきましょう。VS Codeでinherit.rb
というファイルを作成し、以下のコードを書いてみましょう。
class Animal def initialize(name) @name = name end
def speak puts "#{@name}が鳴きます" endend
このコードでは、動物の基本的な機能を持つAnimal
クラスを定義しています。動物の名前を設定するinitialize
メソッドと、動物が鳴く様子を表現するspeak
メソッドを持っています。
では、このAnimal
クラスを継承して、より具体的な動物のクラスを作成してみましょう。
class Dog < Animal def speak puts "#{@name}がワンと鳴きます" endend
class Cat < Animal def speak puts "#{@name}がニャーと鳴きます" endend
ここで重要なのは、クラス定義の際に使用している <
記号です。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}が眠ります" endend
class Dog < Animal def speak puts "#{@name}がワンと鳴きます" endend
class Puppy < Dog def speak puts "#{@name}が可愛くワンと鳴きます" endend
このコードでは、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関係」が成り立つ場合に適している
継承はオブジェクト指向プログラミングの重要な概念の一つです。うまく活用することで、コードの重複を避け、整理された分かりやすいプログラムを作ることができます。しかし、使いすぎるとかえって複雑になることもあるので、クラス間の関係をよく考えて適切に使いましょう。
Starterプランでより詳しく学習
この先のコンテンツを読むにはStarterプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。