【Ruby】レッスン5-09:オーバーライドを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:オーバーライド

この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、メソッド、コレクション(レッスン1~4)クラスの定義と使用イニシャライザアクセスメソッドクラス変数とクラスメソッドprivateメソッド正規表現クラスの継承ファイル操作オーバーライドモジュールの定義と使用ミックスイン

<<前のページ Ruby記事一覧 次のページ>>

Rubyの「オーバーライド」とは

この章ではRubyにおける「オーバーライド」の意味や使い方を学習します。用語の解説が不要な方はここをクリックして練習問題へ飛びましょう。




Rubyではオブジェクト指向プログラミングの一環として「オーバーライド」という機能が提供されています。

この機能を使うと親クラスで定義されたメソッドを子クラスで上書きして独自の動作を実装できます。

初心者にとっても、オーバーライドはクラスの柔軟性を高める重要な技術です。

【初心者向け】Rubyのオブジェクト指向の概念を表した図。特にクラスの継承、オーバーライド、モジュール、ミックスイン、インスタンス生成を視覚的に分かりやすくまとめている。 本記事では「オーバーライド」を中心に説明している。

オーバーライドとは?

オーバーライドとは、親クラスで定義されているメソッドを子クラスで再定義することを指します。

オーバーライドを使用することで、同じ名前のメソッドでも子クラスでは異なる振る舞いを実装できます。これによりコードの再利用性や拡張性が向上します。

Rubyでは、特にsuperキーワードを使って親クラスのメソッドを部分的に利用することも可能です。

オーバーライドの使用例

以下はRubyでオーバーライドを行う具体的なコード例です。

# 親クラスの定義
class Animal
  def speak
    "鳴き声"
  end
end

# 子クラスの定義
class Dog < Animal
  # speakメソッドをオーバーライド
  def speak
    "ワンワン"
  end
end

class Cat < Animal
  # speakメソッドをオーバーライド
  def speak
    "ニャーニャー"
  end
end

# 使用例
dog = Dog.new
puts dog.speak # => "ワンワン"

cat = Cat.new
puts cat.speak # => "ニャーニャー"

この例ではDogおよびCatクラスが親クラスAnimalspeakメソッドをオーバーライドしています。

このように、クラスごとに異なる動作を指定できるのがオーバーライドの強みです。

また、親クラスのメソッドを一部活用したい場合はsuperを使います。

class Dog < Animal
  def speak
    super + "!(元気に鳴いている)"
  end
end

dog = Dog.new
puts dog.speak # => "鳴き声!(元気に鳴いている)"

オーバーライドを使うメリット

オーバーライドを使用する主なメリットは以下の通りです:

  1. コードの再利用: 親クラスのメソッドを基に子クラス独自の動作を追加できるため、コードの重複を減らせます。
  2. 柔軟な拡張性: 子クラスで個別の振る舞いを定義できるため、拡張性の高いプログラムを作成できます。
  3. 可読性の向上: 同じ名前のメソッドを使用しつつクラスのコンテキストごとに異なる動作を定義できるため、コードが直感的になります。

まとめ

Rubyにおけるオーバーライドは、親クラスから継承したメソッドを再定義することでプログラムの柔軟性と再利用性を向上させる重要な技術です。

この機能を活用することで、より効率的で読みやすいコードを書くことができます。

次の章では、さらにオーバーライドを活用した「モジュール」の応用について学びます。

オーバーライドの練習問題

親クラスのメソッドを子クラスでオーバーライドする仕組みを学びましょう。

今回作成するコードではVehicleクラスを親クラスとし、CarクラスとBikeクラスを子クラスとして定義します。

親クラスに2つのメソッドを定義し、そのうち1つは子クラスでオーバーライドしましょう。

もう1つのメソッドはオーバーライドせずにそのまま利用します。これを実装してオーバーライドの挙動を理解してください。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. 親クラスVehicleを作成し、以下のメソッドを定義してください:
    • description: “これは乗り物です。”と出力する。
    • type: “この乗り物は一般的なものです。”と出力する。
  2. 子クラスCarVehicleから継承して定義し、以下を実装してください:
    • descriptionメソッドをオーバーライドし、superを利用して「これは乗り物です。」の後に「 車の種類です。」を追加して出力する。
  3. 子クラスBikeVehicleから継承して定義し、以下を実装してください:
    • descriptionメソッドを完全にオーバーライドし、「これはバイクです。」と出力する。
  4. 子クラスCarBikeでは、親クラスのtypeメソッドをそのまま使用する。
  5. それぞれのインスタンスを作成し、descriptiontypeメソッドを呼び出して結果を確認する。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

これは乗り物です。
この乗り物は一般的なものです。
これは乗り物です。 車の種類です。
この乗り物は一般的なものです。
これはバイクです。
この乗り物は一般的なものです。

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:Vehicleクラスの定義
  □ descriptionメソッドの定義
  □ □ ”これは乗り物です。”という文字列を返す
  □ typeメソッドの定義
  □ □ ”この乗り物は一般的なものです。”という文字列を返す
2:Carクラスの定義(Vehicleクラスを継承)
  □ 親クラスのdescriptionメソッドをオーバーライド
  □ □ superを使用して親クラスのdescriptionメソッドを呼び出し、” 車の種類です。”を追加して返す
3:Bikeクラスの定義(Vehicleクラスを継承)
  □ 親クラスのdescriptionメソッドをオーバーライド
  □ □ ”これはバイクです。”という新しい文字列を返す
4:Vehicleクラスのインスタンスvehicleを作成
  □ vehicle.descriptionメソッドを呼び出し、戻り値を出力
  □ vehicle.typeメソッドを呼び出し、戻り値を出力
5:Carクラスのインスタンスcarを作成
  □ car.descriptionメソッドを呼び出し、戻り値を出力
  □ car.typeメソッドを呼び出し、戻り値を出力

6:Bikeクラスのインスタンスbikeを作成
  □ bike.descriptionメソッドを呼び出し、戻り値を出力
  □ bike.typeメソッドを呼び出し、戻り値を出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

# 親クラス「Vehicle」を定義
class Vehicle
  # 乗り物の詳細を出力するメソッド
  def description
    "これは乗り物です。"
  end

  # 乗り物の種類を出力するメソッド
  def type
    "この乗り物は一般的なものです。"
  end
end

# 子クラス「Car」を定義
class Car < Vehicle
=begin
【穴埋め問題1】
ここに親クラスのdescriptionメソッドをオーバーライドし、superを使って親クラスのメッセージに「 車の種類です。」を追加するコードを書いてください。
=end
end

# 子クラス「Bike」を定義
class Bike < Vehicle
=begin
【穴埋め問題2】
ここに親クラスのdescriptionメソッドをオーバーライドし、完全に新しいメッセージ「これはバイクです。」を出力するコードを書いてください。
=end
end

# オブジェクトを生成し、メソッドを呼び出す
vehicle = Vehicle.new
puts vehicle.description # => これは乗り物です。
puts vehicle.type        # => この乗り物は一般的なものです。

car = Car.new
puts car.description      # => これは乗り物です。 車の種類です。
puts car.type             # => この乗り物は一般的なものです。

bike = Bike.new
puts bike.description     # => これはバイクです。
puts bike.type            # => この乗り物は一般的なものです。

以上がこの問題の穴埋めコードです。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。



練習問題の解答と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

# 親クラス「Vehicle」を定義
class Vehicle
  # 乗り物の詳細を出力するメソッド
  def description
    "これは乗り物です。"
  end

  # 乗り物の種類を出力するメソッド
  def type
    "この乗り物は一般的なものです。"
  end
end

# 子クラス「Car」を定義
class Car < Vehicle
  # descriptionメソッドをオーバーライド
  def description
    super + " 車の種類です。"
  end
end

# 子クラス「Bike」を定義
class Bike < Vehicle
  # descriptionメソッドをオーバーライド
  def description
    "これはバイクです。"
  end
end

# オブジェクトを生成し、メソッドを呼び出す
vehicle = Vehicle.new
puts vehicle.description # => これは乗り物です。
puts vehicle.type        # => この乗り物は一般的なものです。

car = Car.new
puts car.description      # => これは乗り物です。 車の種類です。
puts car.type             # => この乗り物は一般的なものです。

bike = Bike.new
puts bike.description     # => これはバイクです。
puts bike.type            # => この乗り物は一般的なものです。

正解コードの解説

今回のコードはRubyのオブジェクト指向の基本であるオーバーライドの仕組みを学ぶためのものです。

親クラスに定義されたメソッドを子クラスで再定義し、新しい動作を与える方法を解説します。

クラスの定義と親クラスのメソッド

class Vehicle
  def description
    "これは乗り物です。"
  end

  def type
    "この乗り物は一般的なものです。"
  end
end

class Vehicle: 乗り物を表す親クラスを定義しています。このクラスには以下の2つのメソッドがあります。

  • description: 乗り物の基本情報を出力するメソッド。
  • type: 「一般的な乗り物」を示すメッセージを出力するメソッド。このメソッドは子クラスでオーバーライドされません。

子クラスCarでのオーバーライド

class Car < Vehicle
  def description
    super + " 車の種類です。"
  end
end
  1. class Car < Vehicle: Vehicleクラスを継承したCarクラスを定義しています。これにより、Vehicleクラスのメソッドをそのまま使ったり、オーバーライドしたりできます。
  2. descriptionメソッドのオーバーライド:
    • super: 親クラスのdescriptionメソッドを呼び出しています。superを使うことで親クラスのメッセージ「これは乗り物です。」を取得し、それに「 車の種類です。」を追加しています。

子クラスBikeでのオーバーライド

class Bike < Vehicle
  def description
    "これはバイクです。"
  end
end
  1. class Bike < Vehicle: Vehicleクラスを継承したBikeクラスを定義しています。
  2. descriptionメソッドの完全なオーバーライド:
    • 親クラスのdescriptionメソッドを使わず、新しいメッセージ「これはバイクです。」を出力するように再定義しています。

インスタンスの作成とメソッドの呼び出し

vehicle = Vehicle.new
puts vehicle.description # => これは乗り物です。
puts vehicle.type        # => この乗り物は一般的なものです。

car = Car.new
puts car.description      # => これは乗り物です。 車の種類です。
puts car.type             # => この乗り物は一般的なものです。

bike = Bike.new
puts bike.description     # => これはバイクです。
puts bike.type            # => この乗り物は一般的なものです。
  1. Vehicle.new: 親クラスのインスタンスを作成し、descriptiontypeメソッドを呼び出します。
  2. Car.newBike.new: 子クラスのインスタンスを作成し、それぞれのクラスで再定義されたdescriptionメソッドを呼び出します。
    • ポイント: 親クラスから継承したtypeメソッドはオーバーライドされていないため、CarBikeでもそのまま利用できます。

まとめ

このコードではRubyのオブジェクト指向プログラミングにおけるオーバーライドの使い方を学びました。

  • オーバーライドとは: 親クラスで定義されたメソッドを子クラスで再定義し、異なる動作をさせること。
  • superの活用: 親クラスのメソッドを一部利用しながら、独自の動作を追加することが可能。
  • 親クラスの継承: 必要なメソッドを継承することで、コードの重複を防ぎ、柔軟性が向上します。

Rubyのクラスや継承について理解を深める第一歩として、このコードを活用してください!

<<前のページ Ruby記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Rubyのテキスト&問題集トップへ戻る
    トップページへ戻る