OOP(4) 擬似パッケージ SUPER

メソッドのオーバーライドについては昨日勉強しましたが、今日はオーバーライドされたメソッド(親クラスのメソッド)にアクセスする方法を勉強します。
例えば、以下のようなクラスを作ったとします。

package Speaker;
 
sub new {
	my ($class, $name) = @_;
	bless { name => $name }, $class;
}
sub speak {
	my ($self, $msg) = @_;
	print qq("$msg" said $self->{name}.\n);
}

コンストラクタ(new)に話し手の名前を渡し、speak で喋らせる事ができます。
ちなみに qq はダブルクォート("…")と同じ意味で、文字列を括る記号を自由に決める事ができます(qq/…/ や qq|…| など)。開始記号を ( [ { < のような「開きカッコ」にすると、終了記号は対応した「閉じカッコ」になるそうです。
このクラスを Speaker.pm として保存して以下のようなスクリプトを書きます。

use Speaker;
$palmo = Speaker->new("Palmo");
$palmo->speak("Nice to see you!");
$palmo->speak("And see you again!");

実行結果は以下の通りです。

"Nice to see you!" said Palmo.
"And see you again!" said Palmo.

ここで Speaker (話し手)クラスを継承して SneezeSpeaker (くしゃみっぽい話し手)クラスを作りたいとします。この SneezeSpeaker クラスは speak した後に、必ずくしゃみをしてしまうのです。(^_^;)
つまり、以下のようなプログラムで

use Speaker;
$palmo = SneezeSpeaker->new("Palmo");
$palmo->speak("Nice to see you!");
$palmo->speak("And see you again!");

以下のように出力したいのです。

"Nice to see you!" said Palmo.
   "Ha... Haah... HACHOO!"
"And see you again!" said Palmo.
   "Ha... Haah... HACHOO!"

このように「メソッドの振る舞いを変えたい」場合、普通はメソッドをオーバーライドしますが、メソッドをオーバーライドしてしまうと、オーバーライドしてしまった親クラスのメソッド(この場合 Speaker::speak)が呼ばれなくなってしまいます。
もちろん、今回のようなケースなら SneezeSpeaker::speak の中で、喋るメッセージも表示すれば事足りるのですが、後から「やっぱり Palmo said "……". と表示する順番を変えよう」と思い立った時に、2ヶ所変更する事になってしまい、「怠惰で短気で傲慢なプログラマ」としては面白くありません。間違いも起こりやすくなりますね。
こういった場合、Perl では SUPER 擬似パッケージを使って子クラスのメソッド(SneezeSpeaker::sneeze)から親クラスのメソッド(Speaker::speak)を呼び出す事ができるそうです。

package SneezeSpeaker;
our @ISA = ("Speaker");
 
sub speak {
	my $self = shift;
	$self->SUPER::speak(@_);
	print qq(   "Ha... Haah... HACHOO!"\n);
}

Speaker クラスを継承して、SneezeSpeaker クラスを作りました。(Speaker.pm に書き加えました)
speak メソッドでは $self でオブジェクトのリファレンスを受け取ってから、デリファレンスして speak メソッドを呼び出しています。メソッド名の頭に「SUPER::」と付ける事で親クラスのメソッドを呼び出す事ができるそうです。(SUPER は親クラスを表す擬似パッケージ)
注意点としては、SUPER::speak を呼び出す際の引数としてデフォルト配列 @_ をそのまま渡していますが、この配列に「オブジェクトへのリファレンス」が入らないようにする事です。(今回は shift を使って配列から取り除いています)
メインスクリプトで SneezeSpeaker を使うようにした実行結果です。

"Nice to see you!" said Palmo.
   "Ha... Haah... HACHOO!"
"And see you again!" said Palmo.
   "Ha... Haah... HACHOO!"

上手くできました。
最近寒くなったり暑くなったり気温差が激しいので、本当に風邪をひかないようにしなくては。(^_^)