我无法解释多态性在 Perl 中的工作原理。我了解多态性的含义,但我试图弄清楚它在 perl 内部是如何工作的。有人可以向我指出一些解释它的文档。我所做的所有谷歌搜索都给了我关于 perl 中的多态性的例子,而不是 perl 如何使它工作的例子。
5 回答
调用方法时时,Perl 会查看该方法是否由类本身直接提供。
因为类只是 Perl 包,所以只需寻找子例程的存在即可。&Class::method
。
如果没有找到这样的子例程,Perl 会检查@ISA
同一包中的数组(即@Class::ISA
)中包含该类的基类列表的数组,并对其中出现的每个包/类进行相同的检查。
这些类中的每一个也可能有一个@ISA
数组,因此搜索是递归的。
最后,如果这个方法在任何地方都找不到,Perl 会在一个特殊的包UNIVERSAL
中查找一个子例程&UNIVERSAL::method
。
此时失败继续调用AUTOLOAD
系统,但这确实超出了多态性的原则。
在任何地方都找不到合适的匹配方法会引发异常。
来自面向对象的 Perl的第 7 章,Damian Conway,Manning (2000) 被称为多态性。十页。
但是请注意,如果您来自 C++ 或 Java 或 C# 或类似的语言,那么关于 Perl 中的“多态性”的了解并不多。我什至会说多态性的概念使事情比在 Perl 中更复杂。
我认为 Perl 程序员应该努力理解的机制是方法查找的工作原理。答案是:深度优先递归扫描@ISA
包数组。
一个例子,让我们做$o->bla
。我们$o
有幸进入了这个A
包,它没有实现bla
. 但它继承自 firstB
然后C
( @ISA = ('B', 'C')
)。因此,让我们先进行查找B
。它也没有定义方法。如果它有父类,我们会在那里继续查找。但事实并非如此。所以我们现在研究一下C
,幸运的是它确实有方法,否则那将是一个运行时错误,因为最后的包UNIVERSAL
, 也没有定义bla
。
对象方法调用基本上是以下内容的优化*版本:
my $class = ref($_[0]);
my @isa = mro::get_linear_isa($class);
for my $pkg (@isa) {
if (exists(&{$pkg.'::'.$method_name})) {
return &{$pkg.'::'.$method_name};
}
}
ref
获取与对象关联的类的名称。该类存储在对象的变量中。
$ perl -MDevel::Peek -e'my $o = {}; Dump($o); bless($o, "SomeClass"); Dump($o);'
SV = IV(0x9e4ae0c) at 0x9e4ae10
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x9e317d0
SV = PVHV(0x9e36808) at 0x9e317d0
REFCNT = 1
FLAGS = (SHAREKEYS)
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
SV = IV(0x9e4ae0c) at 0x9e4ae10
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x9e317d0
SV = PVHV(0x9e36808) at 0x9e317d0
REFCNT = 1
FLAGS = (OBJECT,SHAREKEYS) <----
STASH = 0x9e323d0 "SomeClass" <----
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
get_linear_isa
是基于@ISA
in package $class
,以及@ISA
其中命名的包的 。
由于类名在对象中,并且由于 Perl 可以在运行时检查其符号表,因此不需要虚拟方法表来提供多态性。
* - 它缓存哪个包为类 $class 提供方法 $method_name。此外,它肯定不会预先计算整个线性 ISA,而是根据需要计算。
这非常适合基于继承的多态性,并给出了 Perl 具体做什么的一些概念。我一直使用第 12.5 章。Perl 编程中的类继承作为这些东西的参考。
多态只是不同类型的对象响应同名方法调用的想法。弱类型语言,例如 Perl,是“隐式多态的”。
例如,一个CGI
对象、一个Apache2::Request
对象和一个Plack::Request
对象都有一个param
返回 HTTP 请求参数的方法。我可以编写一个接受对象作为参数的函数,然后param
在该对象上调用该方法,并获取一个 HTTP 请求参数,而不知道它是什么类型的对象。
强类型语言不能以这种方式工作,因为它们的函数指定了参数的数据类型。Dog
如果它期望Cat
. 所以强类型语言必须创建特殊的机制来允许多态性。