与孩子一起投下的Perl Moose父母班

时间:2011-01-03 10:33:07

标签: perl oop moose

package Point;
use Moose;

has 'x' => (isa => 'Int', is => 'rw');
has 'y' => (isa => 'Int', is => 'rw');

package Point3D;
use Moose;

extends 'Point';

has 'z' => (isa => 'Int', is => 'rw');

package main;

use Data::Dumper;

my $point1 = Point->new(x => 5, y => 7);
my $point3d = Point3D->new(z => -5);

$point3d = $point1;
print Dumper($point3d);

是否可以将父级转换为子类,例如c ++?在我的考试中,$ point3d现在是一个Point而不是Point3D包括Point。

4 个答案:

答案 0 :(得分:5)

查看Class::MOP documentation on CPAN,尤其是clone_objectrebless_instance方法:

sub to_3d {
  my ($self, %args) = @_;
  return Point3D->meta->rebless_instance(
    $self->meta->clone_object($self),
    %args,
  );
}

然后使用它如下:

my $point_3d = $point->to_3d(z => 7);

这也将处理新指定的%args,就像它们已被构造函数传入一样。例如。在此构建期间,都会考虑构建器,默认值和类型约束。

答案 1 :(得分:2)

你不需要使用Perl,因为它是一种动态语言。但是,在您的情况下,变量$point3d包含对脚本末尾的Point对象的引用。您不能将其视为Point3D ,因为它不是Point3D您可以手动转换,但不能“重新制作”将现有对象作为不同的类。 (好吧,理论上你可以用Perl,但你不应该。)

答案 2 :(得分:1)

好吧,Dumper应该告诉您$point3d现在是Point,而不是Point3D,因为您$point3d = $point1的分配使$point3d成为$point1第二次引用与Point3D相同的对象。最初由$point3d引用的Point3D::z($point1, 4)实例现在在空间中丢失,引用计数为0,使其有资格进行垃圾回收。

正如cdhowie所说,你并没有像在C / C ++中那样在Perl中进行类型转换。我能想到的最接近的是回到非OO调用约定并使用,例如,$point1Point3D一个z-index为4,但这有点笨拙而且你是必须使用相同的语法,以便将来引用它的z-index。另请注意,使用此调用约定时,z 必须实际定义Point3D方法[1],否则您将收到运行时错误,因为继承不起作用你是这样做的,因为你将$point1称为包,而不是Point作为对象。

如果您想将Point3D实际变为bless,可以使用AUTOLOAD轻松更改对象的实际类型(用于将普通参考更改为首先是一个对象,虽然它在你的示例代码中隐藏在Moose内部,但我怀疑手动重新使用Moose对象会激怒Moose。 (但是,如果是这种情况,我确信Moose提供了一种更安全的方式来更改对象的类。我只是不要使用Moose来了解它会是什么。)

[1] ......或{{1}},但这是完全不同的蠕虫病毒。

答案 3 :(得分:0)

基本上,我支持cdhowie和Dave S.所说的,但还有一件事需要补充。

如果你想让$point3d将类Point的对象保存到子类Point3D的真实对象中,那么正确的OO方式是通过创建构造函数{ {1}}中的{1}},它将类new_from_Point()的对象作为输入并创建一个Point3D对象(它应该采用额外的“z”参数)。 C ++等价物将是一个签名为Point

的构造函数