I saw 如何重新定义 Perl 类方法? https://stackoverflow.com/questions/635212/how-can-i-redefine-perl-class-methods,所以我想通过一个例子更好地理解它是如何工作的。 (有关的:如何引用方法? - 珀尔蒙克斯 http://www.perlmonks.org/?node_id=62737)
如果我有一个对象$obj
这是一些例子Class
其中有Class::method
, then $obj
也有$obj->method
;我假设在这种情况下简化的内存布局看起来像这样(在LaTeX 表生成器 http://www.tablesgenerator.com/latex_tables#;对于下面的一个,src here https://www.writelatex.com/read/gxwsnjzdxwbg):
...也就是说,在(比如说)地址 0x1000 我们有$obj->method
,这将简单地(以某种方式)指向实际的Class::method
定义,(比如说)位于 0x3500。
假设我有一个sub
在主文件中的某处定义,somefunc
(忽略表中的前缀 $),其定义以地址 0x2000 结束。
如果我“猴子补丁”/仅替换该方法$obj
例如,我希望内存布局看起来像这样(src here https://www.writelatex.com/read/cphsjhfphvtk):
现在的事情是这样的 - 在下面的示例中(东西的命名比上表中的更独特),我实际上想替换整个类方法Demo::My::Functions::test_me
使用主文件中定义的方法repl_test_me
。我真的不知道对地址有何期望,因此我尝试使用以下方法来显示我认为的方法修补之前和之后的地址%p
的说明符printf
。代码输出如下:
$ perl cltest.pl
Starting Demo::Main...
Orig test_me!
1: DMFo: 8e63dc0 DMFo->test_me 8e916f8 DMF::test_me 8e916e8 repl_test_me 8e91748
Orig test_me!
-- CODE --
Subroutine Demo::My::Functions::test_me redefined at cltest.pl line 59.
Repl test_me!
Repl test_me!
2: DMFo: 8e63dc0 DMFo->test_me 8e916f8 DMF::test_me 8dfb708 repl_test_me 8dfb6c8
这里奇怪的是,即使是在主文件中定义的函数,repl_test_me
,更改地址 - 它不应该?!
所以,我显然没有打印我认为的函数地址 - 而且我认为每次调用我都有两个打印输出这一事实也证实了这一点,而我应该只有一个?
如何更改以下代码,以便打印出可以帮助我确认修补/重载是否按预期发生的地址?
这是代码,cltest.pl
:
use v5.10.1;
package Demo::My::Functions;
$INC{'Demo/My/Functions.pm'} = 1;
use warnings;
use strict;
use base 'Class::Accessor';
__PACKAGE__->mk_accessors(qw(test_me));
sub test_me {
my $self = shift;
print("Orig test_me!\n");
return 1;
}
sub test_also_me {
my $self = shift;
print("Orig test_also_me!\n");
return 1;
}
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
############################################################
package Demo::Main;
use warnings;
use strict;
print("Starting Demo::Main...\n");
my $DMFA = Demo::My::Functions->new();
sub repl_test_me {
my $self = shift;
print("Repl test_me!\n");
return 1;
}
# note: \&{$DMFA->test_me} calls!
printf("1: DMFo: %p DMFo->test_me %p DMF::test_me %p repl_test_me %p\n",
$DMFA, \&{$DMFA->test_me}, \&{'Demo::My::Functions::test_me'}, \&repl_test_me
);
print("-- " . ref(\&{$DMFA->test_me}) . " --\n");
{
no strict 'refs';
#~ *Demo::My::Functions::test_me = sub {my $self = shift; print("ReplIN test_me!\n"); return 1; }; # OK
#~ *Demo::My::Functions::test_me = *repl_test_me; # overloads
*Demo::My::Functions::test_me = \&repl_test_me; # overloads
};
# test it:
$DMFA->test_me();
# output addr again:
printf("2: DMFo: %p DMFo->test_me %p DMF::test_me %p repl_test_me %p\n",
$DMFA, \&{$DMFA->test_me}, \&{'Demo::My::Functions::test_me'}, \&repl_test_me
);