How to copy all properties of a class to a new subclass in Perl?
my $t=TT::Pop->new(name => "shadowfax", color => "white");
my $w=TT::Pop::Subs->new($t);
How to write TT::Pop::Subs::new() so that I can make $w cantains all the properties from $t ? In other words, I want to initialize a class with its super class.
In this case, all properties from $t should be readonly, so copy by ref is 开发者_StackOverflow中文版acceptable. (I am not sure whether perl can make those properties readonly)
First, don't call your method new
call it promote
or something like that.
I have mixed feelings about how to handle this design. My initial reaction is that you should use accessor methods and 'manually' copy the values into a new object.
sub promote {
my $class = shift;
my $obj = shift;
my %args = map { $_ => $obj->$_ } qw(
attribute
another
this_one
that_one
);
return $class->new( %args );
}
This insulates your subclass from changes in the parent.
Your parent class may now be or become an inside out object or something else that does not clone
well. A critical attribute in the parent may be replaced by a method that generates it from other attributes.
Obviously, a degree of coupling between a parent and child class is unavoidable. But this approach helps minimize it.
The other way that seems obvious is to use a clone
and rebless like jkramer suggests. The big problem with this is that you have these restrictions:
- your parent class objects must be clonable
- your parent and child classes must implement storage in identically.
- accessor/mutator methods must not use a class-name prefix for attribute access. This means that class Foo stores
attrib
in$self->{'Foo::attrib'} = 'value';
while Foo::Bar stores them in$self->{'Foo::Bar::attrib'} = 'value';
For cloning, I would use Storable
's dclone
. It has the advantage of being a core module, and many more exotic object implementations provide hooks for Storable so that cloning will work properly.
Use Clone to make a deep copy of your data structure and bless the new hash:
use Clone qw(clone);
my $w = bless clone($t), 'TT::Pop::Subs';
Or if you want to create a copy constructor in TT::Pop::Subs:
# In TT::Pop
use base 'Clone';
# In TT::Pop::Subs
sub new {
my ($class, $source) = @_;
return bless $source->clone, $class;
}
Read more about clone here: http://search.cpan.org/~rdf/Clone-0.31/Clone.pm Of course there are many other modules that do the same thing (deep copies of data structures), just pick the one you like best.
sub new {
my $this = shift;
my $class = ref($this) || $this;
my $SuperClass = shift;
my $self = ref($SuperClass)?{%$SuperClass,}:{};
bless $self, $class;
return $self;
}
Well, this makes a copy of the hash.
精彩评论