📜  Perl面向对象

📅  最后修改于: 2021-01-07 08:40:08             🧑  作者: Mango

Perl对象概念

Perl为我们提供了一些构建面向对象系统的工具。 Perl面向对象的概念基于引用,匿名数组和哈希。

Perl基本对象

一个对象只是一个数据结构,它知道它所属的类名。它作为参考存储在标量变量中。相同的标量变量可以仅包含对对象的引用,因此可以将不同的对象包含在不同的类中。

一个就是一个包。它包含对对象进行操作(创建和操作)的方法。

方法是一个子例程,该例程将对象引用或程序包名称作为第一个参数。

Perl类声明

要创建一个类,我们需要在Perl中创建一个包。程序包包含可以重用的变量和子例程。

因为每个类都是一个包,所以它有自己的名称空间,该名称空间由符号名称组成。类是使用package关键字创建的名称空间。通常在与类同名的模块中实现。例如, My ::文件将在File.pm文件中实现,位置将是目录My ,其内容如下。

package My::File;
use strict;
use warnings;
1;

此处的末尾1表示文件已成功加载。

包的范围扩展到文件末尾,或者直到遇到另一个包关键字。

Perl构造函数

代码需要一个功能完整的类的构造函数。

通常,构造函数是作为方法实现的。

sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}

Perl实例/对象

实例或对象主要是对哈希的祝福引用。祝福某事意味着我们祝福该变量所指的事物。

use Scalar::Util 'blessed';
  my $Ana = {};
  my $Christian = $Ana;
  bless $Ana, 'Happiness';
  print blessed( $Christian ) // 'not blessed';    # Class
  print "\n";
  $Christian = "some other value";
  print blessed( $Christian ) // 'not blessed';    # not blessed
  print "\n";  

输出:

Class
not blessed

在上面的程序中,当我们对变量调用“保佑”时,我们保佑变量所指的数据结构。参考没有得到祝福。因此,当我们第二次调用blessed($ Christian)时,它将返回false。因为$ Christian没有存储对对象的引用。

Perl析构函数

Perl析构函数用于在不再需要分配给对象的内存时对其进行清理。当对象超出范围时,它将在Perl中自动完成。因此,它通常不在Perl中实现。

为了实现析构函数,这里有一个称为DESTROY的函数。在Perl销毁对象并回收内存之前调用它。

package MyExample;
sub DESTROY {
   my ($self) = @_;
   print "MyExample::DESTROY called\n";
}

Perl定义方法

在Perl中没有特殊的语法来定义方法。它只是一个常规的子例程,用'sub'关键字声明。

方法将对象或类名作为其第一个参数。

要调用方法,请使用->运算符。

要将方法作为对象调用,使用以下语法:

$object -> method

左边有对象名,右边有方法名。

调用方法时,左侧对象作为第一个参数传递到右侧。

例:

在此示例中,我们将设置一个帮助方法和一个帮助函数来设置学生的姓名和等级。

步骤1hw.pl文件中,定义一个辅助方法studentName以获取学生的姓名。

定义一个辅助函数studentRank以获取学生的排名。

sub studentName {
    return $self->{_name};
}
sub studentRank {
    my ( $self, $name ) = @_;
    $self->{_name} = $name if defined($name);
    return $self->{_name};
}

步骤2student.pm文件中,编写Student package和helper函数。

#!/usr/bin/perl 
package Student;
sub new    
{
    my $class = shift;
    my $self = {
        _name => shift,
        _rank  => shift,   
    };
    # Print all the values just for clarification.
    print "Student's name is $self->{_name}\n";
    print "Student's rank is $self->{_rank}\n";
    
    bless $self, $class;
    return $self;
}
sub studentRank {
    my ( $self, $name ) = @_;
    $self->{_name} = $name if defined($name);
    return $self->{_name};
}
sub studentName {
    my( $self ) = @_;
    return $self->{_name};
}
1;

步骤3person.pl文件中,我们将使用Student对象获取输出。

#!/usr/bin/perl
use Student;
$object = new Student( "Ana", "9th");
# name which is set using constructor.
$name = $object->studentName();
print "Name set using constructor is : $name\n";
# name set using helper function.
$object->studentRank( "Anastasia" );

# getting name set by helper function.
$name = $object->studentName();
print "Name set using helper is : $name\n";

输出:

Student's name is Ana
Student's rank is 9th
Name set using constructor is : Ana
Name set using helper is : Anastasia

Perl继承

继承意味着子类将继承父类的属性和方法。因此,要重用代码,您可以简单地继承它。在Perl中,@ ISA数组定义继承。

使用继承时,应考虑以下几点:

  • 它将搜索给定方法的对象类,即;变量。
  • 它搜索在对象类的@ISA数组中定义的类。
  • 如果在上述步骤中未找到任何方法,它将使用AUTOLOAD子例程。
  • 如果仍然找不到方法,它将使用UNIVERSAL类进行搜索,该类是标准Perl库的一部分。
  • 如果仍然找不到,则会发生运行时异常。

也可以使用指令声明继承,该指令取代了较早的基本指令。

例:

我们的脚本加载一个模块,调用其构造函数,然后调用两个方法。

使用以下脚本创建hw.pl文件。在这里,模块本身使用指令声明其继承。

#!/usr/bin/perl
use strict;
use warnings;
use Module1;
my $myObj = Module1->new;
$myObj->setHello;
$myObj->setBye;

输出:

This is Hello message from Module1
This is Bye message from Module2

使用以下脚本创建Module1.pm文件。它从继承构造函数和其他方法的位置声明模块。

package Module1;
use strict;
use warnings;
use parent 'Module2';
sub setHello {
    print "This is Hello message from Module1\n";
}
1;

使用以下脚本创建Module2.pm文件。

package Module2;
use strict;
use warnings;
sub new {
    my ($class) = @_;
    return bless {}, $class;
} 
sub setBye {
    my ($self) = @_;
    print "This is Bye message from Module2\n";
    return;
}
1;

从Module1调用方法时,Perl不会在Module1中找到它。它将在继承链中的下一个模块Module2中查找它。因此,将从Module2调用新方法。

Perl多态性

多态性意味着基类中定义的方法将覆盖父类中定义的方法。

它附加了现有类的功能,而无需重新编程整个类。

例:

package A;
    sub A1 {
        print("Inside A::A1\n");
    }
package B;
    @ISA = (A);
    sub A1 {
        print("Inside B::B1\n");
    }
package main;
    B->A1();

输出:

Inside B::B1

在类B中定义的子A1覆盖了从类A继承的子类。