Die Definition einer Klasse erfolgt mit dem Schlüsselwort class:
class A def to_s; "ein A"; end end p A.new #-> "ein A"
Innerhalb einer Klasse werden mit def Methoden festgelegt, welche die
von ihr erzeugten Instanzen verwenden können. Die Methode to_s liefert
einen String, der das Objekt repräsentiert. Sie wird von Ruby verwendet, wenn
eine schriftliche Repräsentation des Objekts erstellt werden muss.
Um eine neue Klasse zu erzeugen, die auf einer vorhandenen Klasse aufbaut, wird folgende Syntax verwendet:
class B < A
def to_s
super << "bkömmling"
end
def to_i; 0; end
end
p B.new #-> "ein Abkömmling"
p B.new.to_i #-> 0
p A.new.to_i #-> NoMethodError
Übrigens kann man mit den Operatoren <, >, <= und
>= überprüfen, ob eine Klasse von einer anderen abgeleitet ist:
B > A # B Oberklasse von A? #-> false B < A # A Oberklasse von B? #-> true
Mit super wird die gleichnamige Methode der Oberklasse aufgerufen.
Dieser Aufruf wird vor allem dann verwendet, wenn man in einer abgeleiteten
Klasse zur in der Oberklasse vorhandenen Funktionalität etwas hinzufügen
möchte. Methoden, die in der Unterklasse hinzugefügt oder überschrieben
werden, beeinflussen die Oberklasse nicht.
Um ein Objekt mit einer Instanzvariablen zu bestücken, reicht es, diese "`irgendwann"' zu verwenden:
class C def ivar; @ivar; end def ivar=(value); @ivar = value; end end c = C.new c.ivar #-> nil c.ivar = 5 #-> 5 c.ivar #-> 5
Es kommt oft vor, dass man der Außenwelt Zugriff auf die Instanzvariablen
eines Objekts gewähren will. Wenn es reine Lese- und Schreibmethoden sind,
wie im oberen Beispiel, kann man auch folgendes (zu oben gleichwertiges)
Verfahren verwenden:
class C2 attr_reader :ivar attr_writer :ivar end #oder class C3 attr_accessor :ivar end
Da Klassendefinitionen in Ruby ausführbarer Code sind, muss der Interpreter
Konstruktionen wie die attr-Funktionen nicht gesondert
behandeln.
Sie funktionieren ähnlich wie Makros in Common Lisp und sind
eigentlich Methoden, die das erzeugte
Class-Objekt von seiner Oberklasse Module geerbt hat.
Anhand der Implementation der attr_reader-Methode sei erklärt, wie Ruby
auf Grund seiner mächtigen Reflektionsmechanismen (siehe
Kapitel 17) diese Aufgabe lösen kann.
class Module\noskip
def attr_reader(*method_symbols)
method_symbols.each { | method |
module_eval(
"def #{method}; return @#{method}; end")
}
end
end
Gelegentlich benötigt man Klassenvariablen, die einen instanzunabhängigen Wert
speichern. Solche Klassenvariablen müssen vor dem ersten Lesezugriff
initialisiert werden. Im folgenden Beispiel lassen wir zählen, wie viele
Instanzen einer Klasse schon erzeugt wurden. Die Methode initialize
wird beim Erzeugen einer neuen Instanz automatisch aufgerufen.
class D @@nr = 0 def initialize; @@nr += 1; end def D.status; puts @@nr; end end 1.upto(rand 10) do D.new end D.status
Neben Instanzmethoden, die sich an ein bestimmtes Objekt einer Klasse richten, gibt es noch Klassenmethoden, die eine Klasse als Empfänger haben. Nun sind aber Klassen in Ruby auch nur Instanzen der Klasse Class, so dass es keinen fundamentalen Unterschied zwischen Instanz- und Klassenmethoden gibt.
Um eine solche Klassenmethode
zu definieren, wird in der def-Anweisung der Klassenname eingefügt.
Im obigen Beispiel wird D.status unabhängig von Instanzen der
Klasse aufgerufen.