7

我无法解释多态性在 Perl 中的工作原理。我了解多态性的含义,但我试图弄清楚它在 perl 内部是如何工作的。有人可以向我指出一些解释它的文档。我所做的所有谷歌搜索都给了我关于 perl 中的多态性的例子,而不是 perl 如何使它工作的例子。

4

5 回答 5

15

调用方法时时,Perl 会查看该方法是否由类本身直接提供。

因为类只是 Perl 包,所以只需寻找子例程的存在即可。&Class::method

如果没有找到这样的子例程,Perl 会检查@ISA同一包中的数组(即@Class::ISA)中包含该类的基类列表的数组,并对其中出现的每个包/类进行相同的检查。

这些类中的每一个也可能有一个@ISA数组,因此搜索是递归的。

最后,如果这个方法在任何地方都找不到,Perl 会在一个特殊的包UNIVERSAL中查找一个子例程&UNIVERSAL::method

此时失败继续调用AUTOLOAD系统,但这确实超出了多态性的原则。

在任何地方都找不到合适的匹配方法会引发异常。

于 2012-06-13T17:47:57.517 回答
9

来自面向对象的 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

于 2012-06-13T17:57:20.380 回答
5

对象方法调用基本上是以下内容的优化*版本:

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是基于@ISAin package $class,以及@ISA其中命名的包的 。

由于类名在对象中,并且由于 Perl 可以在运行时检查其符号表,因此不需要虚拟方法表来提供多态性。

* - 它缓存哪个包为类 $class 提供方法 $method_name。此外,它肯定不会预先计算整个线性 ISA,而是根据需要计算。

于 2012-06-13T18:22:22.530 回答
1

这非常适合基于继承的多态性,并给出了 Perl 具体做什么的一些概念。我一直使用第 12.5 章。Perl 编程中的类继承作为这些东西的参考。

于 2012-06-13T17:20:21.577 回答
1

多态只是不同类型的对象响应同名方法调用的想法。弱类型语言,例如 Perl,是“隐式多态的”。

例如,一个CGI对象、一个Apache2::Request对象和一个Plack::Request对象都有一个param返回 HTTP 请求参数的方法。我可以编写一个接受对象作为参数的函数,然后param在该对象上调用该方法,并获取一个 HTTP 请求参数,而不知道它是什么类型的对象。

强类型语言不能以这种方式工作,因为它们的函数指定了参数的数据类型。Dog如果它期望Cat. 所以强类型语言必须创建特殊的机制来允许多态性。

于 2012-06-13T20:46:07.040 回答