今日の教科書
継承
#継承
すでに定義されているクラスから機能を引き継いで新しいクラスを作ること。
作るときにスーパークラス(親クラス)となるクラスを指定すると継承できる。
class サブクラス < スーパークラス
本体
end
継承で新しく作られたクラスをサブクラス、継承元のクラスをスーパークラスと呼ぶ。
スーパーにできるのは一つだけ!
class Foo
def foo
puts("foo")
end
end
class Bar < Foo
def bar
puts("bar")
end
end
bar = Bar.new
bar.foo #=> foo
bar.bar #=> bar
継承によってサブクラスができること
- スーパーの機能を全て使用でき、新しい機能を追加
- スーパーの機能を上書きして、同じ名前のメソッドを作れる
- スーパーの機能を呼び出して、その機能に処理を追加して拡張
#is_a?メソッド
サブクラスとスーパークラスの関係を「is-aの関係」といいます。is_a?メソッドを使うことによって、レシーバに指定したオブジェクトがクラスに属しているのかを判定できます。is_a?メソッドは継承関係をさかのぼって、レシーバがクラスに属しているかを調べることができます。
class Foo
end
class Bar < Foo
end
class Baz < Bar
end
baz = Baz.new
baz.is_a?(Baz)
baz.is_a?(Bar)
baz.is_a?(Foo)
#オーバーライド
継承でスーパークラスの機能をサブに提供する。
class Foo
def foo
puts("foo")
end
end
class Bar < Foo
def foo
puts("override")
end
end
bar = Bar.new
bar.foo #=> override
同じ名前のメソッドをサブで定義する。
サブで同じ名前のメソッドを定義し直すことをオーバーライドという。
これでスーパーのメソッドをサブで書き換えることが可能。
オーバーライドのメソッドをサブで呼び出すこともできる。
class Foo
def foo
puts("foo")
end
end
class Bar < Foo
def foo
super
puts("foo")
super
end
end
bar = Bar.new
bar.foo
super
:オーバーライドされたメソッドの元の振る舞いを呼び出す。
サブでオーバーライドしたメソッドは、コードのコピーを行わず機能を拡張できる。
class Foo
def foo(args=5)
p args * 2
end
end
class Bar < Foo
def foo(args=2)
super(10)
super
super()
end
end
bar = Bar.new
bar.foo
#=> 20
#=> 4
#=> 10
superに引数を与えることもできる。引数を指定しない場合、デフォルト値が渡される。
引数なしでオーバーライドのメソッドを呼ぶにはsuper()と書く。
()なしだと、サブクラスのオーバーライドしたメソッドの引数のデフォルト値が渡される。
##superclass
あるクラスのスーパーを知りたい場合、superclassメソッドを使う。
class Foo
end
class Bar < Foo
end
p Bar.superclass #=> Foo
#アクセス制限
https://www.javadrive.jp/ruby/private/index1.html
Rubyにおける可視性とは、主にメソッドの可視性に関する話です。言い換えると、Rubyの可視性とはメソッドをどこから呼び出せるかについて設定をおこなう機能です。
クラスの中でメソッドを定義すると、インスタンスメソッドとして呼び出すことができます。ただし、クラスの内部だけでしか使わない(外部に公開する予定の無い)メソッドも同じように呼び出せては困ります。そのような時に以下のメソッドを使うことによって、メソッドの可視性を変えることができます。
public
private
protected
これらを指定するには、以下のようなやり方があります。
引数にメソッド名をシンボルで指定して、メソッドの可視性を変える
引数を与えずにメソッドを呼び出して、可視性のデフォルトの設定を変える
publicに設定されたメソッドは、パブリックメソッドと呼びます。privateに設定されているメソッドのことを、プライベートメソッドと呼び、protectedに設定されているメソッドのことを、プロテクテッドメソッドと呼びます。
def foo
puts("foo")
end
public :foo
private :foo
class Foo
public
def foo
puts("foo")
end
private
def bar
puts("bar")
end
protected
def baz
puts("baz")
end
end
クラスの中で定義したメソッドは(initializeメソッドを除いて)、何も設定をしていない状態だとpublicになります。publicはメソッドを呼び出すのにまったく制限がないことを表します。そのため、どこからでもpublicに設定されているメソッドは呼び出せます。privateはメソッドを定義したクラスの中か、そのクラスを継承したサブクラスのメソッドの中で呼び出せます。つまり、プライベートメソッドはオブジェクトの外側から使えません。
class Foo
private
def foo
puts("foo")
end
end
class Bar < Foo
def call_foo
foo
end
end
bar = Bar.new
bar.call_foo
protectedはprivateと似ていますが、プロテクテッドメソッドは、クラス(またはそのクラスのサブクラス)に属してる各オブジェクトから呼び出せます。レシーバを指定した形やレシーバを指定しない形(つまり、関数的なメソッド)のどちらでも呼び出せます。
class Foo
protected
def foo
puts("Protected Method foo")
end
private
def bar
puts("Private Method bar")
end
public
def useFoo(o)
o.foo
end
def useBar(o)
o.bar
end
end
fooReciever = Foo.new
fooSender = Foo.new
fooSender.useFoo(fooReciever) # "Protected Method foo"が表示される
fooSender.useBar(fooReciever) # NoMethodErrorが発生します