Perl Moose 父类与子类一起演员表

发布于 2024-10-09 18:45:46 字数 497 浏览 13 评论 0原文

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,而不是包含 Point 的 Point3D。

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);

Is it possible to cast a parent to child class such as c++? In my examble is $point3d now a Point and not a Point3D include the Point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

勿挽旧人 2024-10-16 18:45:46

看一下 类:: CPAN 上的 MOP 文档,特别是 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 就像它们是由构造函数传入的一样。例如,构建器、默认值和类型约束都在此构建过程中考虑。

Take a look at the Class::MOP documentation on CPAN, especially the clone_object and rebless_instance methods:

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

And then use it like the following:

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

This will also take care to treat the newly specified %args as if they've been passed in by the constructor. E.g. builders, defaults, and type constraints are all considered during this build.

冷弦 2024-10-16 18:45:46

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

You do not need to cast in Perl, since it is a dynamic language. In your case though, the variable $point3d contains a reference to a Point object at the end of the script. You cannot treat this as a Point3D because it is not a Point3D. You could manually convert it, but you can't "remake" an existing object as a different class. (Well, you theoretically can in Perl, but you shouldn't.)

深白境迁sunset 2024-10-16 18:45:46

好吧,Dumper 应该告诉您 $point3d 现在是一个 Point,而不是 Point3D,因为您的分配$point3d = $point1 使 $point3d 成为对与 $point1 相同的对象的第二个引用。最初由 $point3d 引用的 Point3D 实例现在丢失在空间中,引用计数为 0,使其符合垃圾回收条件。

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

如果您想实际将 Point 变成 Point3D,您可以使用 bless 轻松更改对象的实际类型(与使用的命令相同)首先将普通引用更改为对象,尽管它隐藏在示例代码中的 Moose 内部),但我怀疑手动重新祝福 Moose 对象会激怒 Moose。 (但是,如果是这种情况,我确信 Moose 提供了一种更安全的方法来更改对象的类。我只是没有充分使用 Moose 来知道它会是什么。)

[1] ...或 AUTOLOAD,但那是完全不同的蠕虫病毒。

Well, Dumper should tell you that $point3d is now a Point, not a Point3D, because your assignment of $point3d = $point1 makes $point3d a second reference to the same object as $point1. The Point3D instance that was originally referenced by $point3d is now lost in space with a refcount of 0, making it eligible for garbage collection.

As cdhowie said, you don't really do typecasting in Perl the way you do in C/C++. The closest I can think of is to fall back on the non-OO calling convention and use, e.g., Point3D::z($point1, 4) to give $point1 a z-index of 4, but that's kind of clumsy and you'd have to use the same syntax for any future references to it's z-index. Note also that, when using this calling convention, Point3D must actually define a z method[1] or you'll get a runtime error because inheritance doesn't work when you do it this way because you're referring to Point3D as a package, not to $point1 as an object.

If you want to actually make your Point into a Point3D, you can easily change the actual type of an object using bless (the same command used to change a plain reference into an object in the first place, although that's hidden inside of Moose in your example code), but I suspect that manually reblessing a Moose object would anger the Moose. (But, if that is the case, I'm sure Moose provides a safer way of changing an object's class. I just don't use Moose enough to know what it would be.)

[1] ...or AUTOLOAD, but that's an entirely different can of worms.

瑾兮 2024-10-16 18:45:46

基本上,我赞同 cdhowie 和 Dave S. 的说法,但还要补充一件事。

如果你确实想将包含类 Point 的对象的 $point3d 变成子类 Point3D 的真实对象,那么正确的 OO 方法它是通过在 Point3D 类中创建一个构造函数 new_from_Point() 来获取 Point 类的对象作为输入并创建一个 Point3D 对象(它可能需要一个额外的“z”参数)。 C++ 等效项是一个签名为 (const Point &, double &z=0.0) 的构造函数

Basically, I am seconding what cdhowie and Dave S. said, but one more thing to add.

If you DO want to make $point3d which holds an object of class Point into a real object of subclass Point3D, the correct OO way of doing it is by creating a constructor new_from_Point() in Point3D class, which takes an object of class Point as input and creates an Point3D object (it should probably take an extra "z" parameter). The C++ equivalent would be a constructor with a signature of (const Point &, double &z=0.0)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文