4部 オブジェクト指向

オブジェクト指向の継承

オブジェクト指向では、オブジェクトは「物」の概念をもとにしていると説明しましたが、オブジェクト指向はモノだけではなく、「継承」といった、生物的な概念も利用しています。
クラスはその子供のサブクラスに、メソッドを引き継がせることができます。親クラスをスーパークラスと呼びますが、スーパークラスで定義したメソッドは、そのままサブクラスで使うことができます。また、上書きすることもできます。スーパークラスは1つである必要がなく、複数のスーパークラスから派生したサブクラスも作成できます。

クラスを継承する

オブジェクト指向の「継承」を使えば、元のクラスの資源をもとに、新しいクラスを簡単に作成することができます。オブジェクト指向では、元になるクラスをスーパークラス、それから派生したクラスをサブクラスと呼びます。

@ISAを使って継承する

既存のクラスを継承してサブクラスを定義するには、サブクラス内で @ISAにスーパークラスの名前をセットします。

まずは、ClassA.pm という名前でスーパークラスを作成しましょう。

# ClassA を宣言(ClassB のスーパークラスになります)
package ClassA;
# コンストラクタの作成
sub new {
	my $class = shift;
	my $self = { x => 10 };
	bless $self,$class;
}
# メソッドの作成
sub print_x{
	my $self = shift;
	print $self->{x}, "\n";
}
1

次に、ClassB.pm という名前でサブクラスを作成します。

# ClassB を宣言
package ClassB ;
# パッケージAの使用を宣言
use ClassA;
# @ISAにスーパークラスの名前「A」を設定
# これによってクラスBはクラスAを継承する
@ISA = qw ( ClassA );
# ClassB のコンストラクタ
sub new {
	my $class = shift;
	# ClassA のコンストラクタを呼び出す
	my $self = new ClassA;
	return bless $self;
}
1

これだけで継承が終わりました。上記のクラスB は、クラスA のメソッドを全て受け継いでいます。
それでは、ClassBのコンストラクタに注目してください。クラスに属したオブジェクトの作成で、ClassAのコンストラクタを呼び出しています。ClassA から返されたオブジェクトリファレンスをそのままClassBのインスタンス変数として bless しています。これで、ClassAのメソッド、インスタンス変数がすべてアクセス可能になりました。

ClassBを呼び出し、ClassAの print_x メソッドを利用するには次のようになります。

use ClassB;
my $obj = new ClassB;
# メソッドの読み出し
$obj->print_x;

呼び出し側では、print_x メソッドがClassAとClassBのどちらかで定義されているかを気にする必要はありません。ただ呼び出すだけです。

スーパークラスのメソッドをオーバーライドする

スーパークラスのメソッドと同名のメソッドを定義することを、「オーバーライド」と呼びます。変数に新しい値を代入するのと同じように、スーパークラスのメソッドを上書きできます。

スーパークラスのメソッドをオーバーライド

以下の例は、スーパークラスのメソッドをオーバライドし、オーバライドされた後でそのメソッドを呼び出しています。

#--------------------------------------#
# スーパークラスを定義
package Unix;
sub print_x {
	print "UNIX! \n"
}
#--------------------------------------#
# サブクラスを定義
package Linux;
@ISA = qw( Unix );
sub new { bless {} }
sub print_x {
	print "LINUX! \n"
}
#--------------------------------------#
package main;
my $obj = new Linux;
$obj->print_x;

オーバーライドした元のメソッドを使う

サブクラスでオーバーライドされた元のメソッドは、スーパークラスを表す SUPER という擬似クラスで呼び出せます。

# スーパークラスの new メソッド呼び出し
my $obj = $class->SUPER::new( $x, $y );

これでスーパークラスのコンストラクタ newメソッドが実行されます。スーパークラスのメソッドを呼び出すには、「クラス名::メソッド名」とします。モジュールからサブルーチンを参照する方法と同じ記法ですね。

多重継承

配列@ISAには複数のクラス名を設定することが出来ます。この場合、2個以上のクラスからメソッドを継承することになります。これを『多重継承』といいます。
多重継承の場合、@ISAに設定されたスーパークラスを1つづつ順に並べて、起動すべきメソッドを探します。

#--------------------------------------#
# スーパークラスを定義
package Unix;
sub unix { print "UNIX! \n" }
#--------------------------------------#
# サブクラスを定義
package Linux;
@ISA = qw( Unix );
sub linux {
	print "Linux! \n"
}
#--------------------------------------#
package BSD;
sub bsd {
	print &	quot;BSD! \n"
}
#--------------------------------------#
#
package Foo;
@ISA = qw( Linux BSD );
@Foo::Inherit::ISA = @ISA; # オーバライドされたメソッドのアクセス
sub new { bless [] }
sub unix {
	my $self = shift;
	$self->Foo::Inherit::unix();
}
sub linux {
	my $self = shift;
	$self->Foo::Inherit::linux();
}
sub bsd {
	my $self = shift;
	$self->Foo::Inherit::bsd();
}
sub os_x {
	print "OS X!\n"
}
#--------------------------------------#
package main;
$foo = new Foo;
$foo->linux;
$foo->bsd;
$foo->os_x;

出力結果は下記のとおりです。

Linux!
BSD!
OS X

関連記事