【问题标题】:Perl: Using common constructor for base and subclassPerl:对基类和子类使用通用构造函数
【发布时间】:2013-10-11 17:46:00
【问题描述】:

我正在尝试初始化一个基类和一个子类,而不必复制构造函数。这是我得到的:

tstbase.pm:

package tstbase;
use Exporter qw(import);
our @EXPORT = qw(&new);
my %config = (
    "class" => "tstbase",
);

sub new {
    my $class = shift;
    my $self;
    $self->{"name"} = $config{"class"};
    bless ($self, $class);
    return $self;
};
1;

tstsubclass.pm:

package tstsubclass;
use tstbase;
my %config = (
  "class" => "tstsubclass",
);
1;

tst.pl:

#!/usr/bin/perl
use tstsubclass;

my $baseobj = tstbase->new;
print "Testbase ".$baseobj->{"name"}."\n";
my $subobj = tstsubclass->new;
print "Testsubclass ".$subobj->{"name"}."\n";

tst.pl 的输出是

Testbase tstbase
Testsubclass tstbase

但我正在寻找

Testbase tstbase
Testsubclass tstsubclass

当我将“sub new { ..}”例程复制到 tstsubclass.pm 时得到的。有没有办法避免这种开销?我已经尝试了我的 %config / 我们的 %config 和导出 %config 的所有组合,但没有成功。

非常感谢任何帮助

最好, 马库斯

【问题讨论】:

    标签: perl class constructor shared


    【解决方案1】:

    您的构造函数是继承的,所以可以正常工作。不起作用的是您使用%config,它单独存在于每个包中。因为您正在调用基类中定义的构造函数,所以使用了该版本的%config。在您的特定情况下,配置哈希是不必要的,因为您可以使用传递给构造函数的 $class 变量来初始化 name 成员:

    sub new {
        my $class = shift;
        my $self = { };     # initialize the object as a reference to an empty hash
        $self->{"name"} = $class;
        bless ($self, $class);
        return $self;
    };
    

    这会起作用(尽管没有必要;您总是可以使用Scalar::Util::blessed 获取对象的类)。

    但更普遍的问题似乎是关于如何在继承的构造函数中使用特定于类的配置信息。一种方法是使用可以在子类中覆盖的单独初始化步骤。

    package tstbase;
    
    # we don't use Exporter for OO code; exporting methods is highly counterproductive.
    # we should also turn on strict and warnings.
    use strict;
    use warnings;
    
    my %config = (
        "class" => "tstbase",
    );
    
    sub new {
        my $class = shift;
        my $self;
        bless $self, $class;
        $self->_init( %config );
        return $self;
    };
    
    sub _init { 
        my $self = shift;
        my %args = @_;
        $self->{name} = $args{class};
    }
    
    1;
    

    然后:

    package tstsubclass;
    use parent 'tstbase';   # we have to say what class we're extending
    
    my %config = (
      "class" => "tstsubclass",
    );
    
    sub _init { 
        my $self = shift;
        $self->SUPER::_init( %config );
    }
    
    1;
    

    在这种情况下,您的子类的_init 方法将被父类中的构造函数调用,该构造函数调用父类的_init 方法,但传入其本地%config

    更简单的处理方法是使用 mixin 或 Moose 角色。

    【讨论】:

    • 感谢您的快速回复!正如您可能怀疑的那样,我的目标不是能够访问类名,而是对类属性执行一些复杂的初始化——我刚刚发布了精简的示例。原来的类构造函数有 80 行代码。我会检查这种方法是否能解决我的问题。无论如何,你解决了这个问题,所以竖起大拇指!
    猜你喜欢
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 2014-02-19
    • 2016-07-19
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    相关资源
    最近更新 更多