Perl でオブジェクト指向 C++風 その2 クラス変数
先の記事で「パッケージ」でインポートした関数などを、「クラス」で使う方法を書いた。本稿では同方法で、「クラス変数」をどのように実現するか例示する。
■方法1:$class->get_template()->{cvar} を使う。
Main::_Simple までは先の記事とほぼ同じで、次のようにすれば「クラス変数」を継承先で共有できる。(動くソースはexample_oo_c1.pl。)
{
package Main::_C1;
use base qw(Main::_Simple);
our $classvar_1 = 0; # クラス変数の実体、このままでは「継承」されない。
__PACKAGE__->extend_template
(
member_1 => 1.0, # ここに member_1 の説明を書こう!
cvar_1 => \$classvar_1, # クラス変数の登録
);
sub method_2 { # クラス変数を print するだけ。
my $self = shift;
print ${ref($self)->get_template()->{cvar_1}} . "\n";
}
}
{
package Main::_C2;
use base qw(Main::_C1);
}
MAIN:
{
my $c1 = Main::_C1->new();
my $c2 = Main::_C2->new();
$c1->method_2(); # 0 と表示。
$c2->method_2(); # 0 と表示。
${Main::_C1->get_template()->{cvar_1}} = 1;
$c2->method_2(); # C1 を変えたのに c2 が 1 と表示。
${Main::_C2->get_template()->{cvar_1}} = 2;
$c1->method_2(); # C2 を変えたのに c1 が 2 と表示。
}
実行結果はなんの<ruby><rb>衒</rb><rt>てら</rt></ruby>いもなく以下のようになる。
$ perl example_oo_c1.pl
0
0
1
2
extend_template は dclone していないため、このようなことができる。
もちろん、$c1 を new するときは、dclone が呼ばれているため、 $c1->{cvar_1} は Main::_C2->get_template()->{cvar_1} とは別の(スカラ変数の)参照を持ってしまい、その分、メモリが無駄になる。
肯定的にとらえれば、$c1 が生成されたときのクラスの状況は自動的に転写されるため、当初との違いが必ず比較されうるというプレッシャーをクラスの管理人(だいたい自分)に与えることができるといえよう。
■方法2:コンストラクタを使う。
Main::_Simple までは先の記事とほぼ同じで、今度はコンストラクタを使って、「クラス変数」の格納場所を一種のオブジェクトとみなし、常にコンストラクタで登録していく。(動くソースはexample_oo_c2.pl。)
{
package Main::_C1;
use base qw(Main::_Simple);
our $classvar_1 = 0; # クラス変数の実体、このままでは「継承」されない。
__PACKAGE__->extend_template
(
member_1 => 1.0, # ここに member_1 の説明を書こう!
cvar_1 => undef, # ここにはクラス変数の参照が入る。
);
sub method_2 { # クラス変数を print するだけ。
my $self = shift;
print ${$self->{cvar_1}} . "\n";
}
sub new {
my $class = shift;
my $obj = $class->SUPER::new(@_);
$obj->{cvar_1} = \$classvar_1;
return $obj;
}
}
{
package Main::_C2;
use base qw(Main::_C1);
}
MAIN:
{
my $c1 = Main::_C1->new();
my $c2 = Main::_C2->new();
$c1->method_2(); # 0 と表示。
$c2->method_2(); # 0 と表示。
${$c1->{cvar_1}} = 1;
$c2->method_2(); # C1 を変えたのに c2 が 1 と表示。
${$c2->{cvar_1}} = 2;
$c1->method_2(); # C2 を変えたのに c1 が 2 と表示。
}
実行結果は上の例と同じである。
ただ、この方法を使うなら、わざわざ「クラス変数」の参照にする必要はない。つまり、our $classvar_1 に直接、オブジェクトを代入しておき、それをコンストラクタで常に新しいオブジェクトに登録するようにすればいいのである。
「クラス変数」にオブジェクトを入れたくなったら、その前に、少し考えて欲しい。コンストラクタを使うなら、あるオブジェクトを、継承された全オブジェクトで共有するのは簡単なのだから。
逆に考えれば、「クラス変数」は、文字列や数値を「環境変数」的に利用したい場合にのみ使うに留めるべきだと、私は、思う。
■関連
●example_oo_pl.shar。上のリンクしたソースやその他の例をまとめたアーカイブ。(シェルアーカイブ形式。シェルコマンドとして実行するか unshar を使う。)
●《Perl でオブジェクト指向 C++風》。「先の記事」。
●《404 Blog Not Found:perl - Inside-out Object》。簡単なシミュレーションが私の目的で、その場合、勝手にクラスは定義するけど、デフォルトにないモジュールは使わず、一つのファイルを見れば済むもののほうが良い…という思いを私は強くしている。ただ、複数人で開発するなど、モジュール分割が必要で、速度や様式を揃える必要があるというなら、このリンク先にチラと紹介されてる Class::Std など、すでにあるものを元にすべきなのだろう。(同ブログは、日本の Perl プログラマの集るところ。私の記事が理解できるならもう知っているだろうが、一つぐらいはリンクしておきたかった。この記事の関連だと、次の記事の理論が興味深い。《404 Blog Not Found:オブジェクトは難しくない。難しいのはクラス》。)
更新:2011-01-06
初公開:2011年01月06日 13:13:56
最新版:2011年01月06日 22:27:12
Trackbacks:
《Perl でオブジェクト指向 C++風 その3 ローカル関数》 from JRF のソフトウェア Tips
先の記事で「パッケージ」でインポートした関数などを、「クラス」で使う方法を書いたが、インポートした関数の他に、Main パッケージで定義した「ローカル関数」も「クラス」で使いたくなるのが当然である。(というより、それができないことにさっき気付いた。)本稿ではほぼソースだけだがその方法を示す。...
受信: 2011-01-07 22:45:05 (JST)
Links:
先の記事: http://jrf.cocolog-nifty.com/software/2010/12/post.html
example_oo_c1.pl: /archive/example_oo/example_oo_c1.pl
example_oo_c2.pl: /archive/example_oo/example_oo_c2.pl
example_oo_pl.shar: /archive/example_oo/example_oo_pl.shar
Perl でオブジェクト指向 C++風: http://jrf.cocolog-nifty.com/software/2010/12/post.html
404 Blog Not Found:perl - Inside-out Object: http://blog.livedoor.jp/dankogai/archives/50783623.html (hbm)
404 Blog Not Found:オブジェクトは難しくない。難しいのはクラス: http://blog.livedoor.jp/dankogai/archives/50689356.html (hbm)