Rubyの勉強 (5) - クラス
クラスの定義
クラスの定義はclass〜end
class Hello
def hello(str)
puts "Hello, #{str}"
end
end
if __FILE__ == $0
Hello.new.hello("Ruby") # Hello, Ruby
endnewでオブジェクトを生成する.メソッドの呼び出しは.を用いる.__FILE__はそれが書かれているファイル名,$0は実行中のスクリプト名なので,このスクリプトをそのまま実行したときはif文が実行される.
オブジェクト生成時にはnewの引数がinitializeに渡され実行される.
class Hello
def initialize(str)
@str = str
end
def hello()
puts "Hello, #{@str}"
end
end
if __FILE__ == $0
Hello.new("Ruby").hello() # Hello, Ruby
end
継承
継承は'<'を用いて行う.perldoc perlbootを参考にした.動物をクラス化している.
class Animal
def speak
puts "a #{self.class} goes #{self.sound}!"
end
def sound
"unknown"
end
end
class Cow < Animal
def sound
"moooo"
end
end
class Horse < Animal
def sound
"neigh"
end
end
class Sheep < Animal
def sound
"baaaah"
end
end
if __FILE__ == $0
for a in [Cow, Horse, Sheep]
a.new.speak
end
end$ ruby animal.rb a Cow goes moooo! a Horse goes neigh! a Sheep goes baaaah!
アクセサ
そのままインスタンス変数を返すだけならばattr_readerメソッドを実行することでそのインスタンス変数の値を返すアクセサを生成することができる.
class Animal
attr_reader :sound
def initialize(sound)
@sound = sound
end
def speak
puts "a #{self.class} goes #{self.sound}!"
end
end
class Cow < Animal
def initialize
@sound = "mooo"
end
end
class Horse < Animal
def initialize
@sound = "neigh"
end
end
class Sheep < Animal
def initialize
@sound = "baaaah"
end
end
if __FILE__ == $0
for c in [Cow, Horse, Sheep]
a = c.new
puts "#{a.class} ==> #{a.sound}"
end
end
インスタンス変数への代入
演算子=をオーバーライドすることでインスタンス変数への代入を行える.
class Animal
def initialize(sound)
@sound = sound
end
def sound
@sound
end
def sound=(sound)
@sound = sound
end
end
if __FILE__ == $0
a = Animal.new("boo")
puts a.sound # boo
a.sound = "oink"
puts a.sound # oink
endattr_writerを用いることで自動生成できる
class Animal
attr_reader :sound
attr_writer :sound
def initialize(sound)
@sound = sound
end
endというか,attr_accessorで読み取り書き込みの両方ができる
class Animal
attr_accessor :sound
def initialize(sound)
@sound = sound
end
end
クラス変数とクラスメソッド
カウンタを作ってみる.カウンタごとに何回数えたかを表すインスタンス変数@countと全てのカウンタで何回カウントしたかを表すクラス変数@@total_countを用いている.クラスメソッドは「クラス名.メソッド名」で定義する.
class Counter
attr_reader :count
@@total_count = 0
def initialize(n=0)
@count = n
end
def inc
@count += 1
@@total_count += 1
end
def Counter.total_count
@@total_count
end
end
if __FILE__ == $0
c1 = Counter.new
c2 = Counter.new(2)
puts "c1: #{c1.count}" # 0
puts "c2: #{c2.count}" # 2
puts "Total: #{Counter.total_count}"
c1.inc
c2.inc
puts "c1: #{c1.count}" # 1
puts "c2: #{c2.count}" # 3
puts "Total: #{Counter.total_count}" # 2
end
アクセス制御
アクセス制御はC++と同じようにpublic,protected,privateがあるデフォルトではpublic.privateにしたい場合は以下のようにする.
class Sample
def foo
puts "this is private"
end
def bar
puts "this is public"
end
private :foo
end
if __FILE__ == $0
s = Sample.new
s.bar
s.foo
end
$ ruby private.rb this is public private.rb:14: private method `foo' called for #<Sample:0x1d3300> (NoMethodError)