Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > как наследовать конструктор


Автор: gcc 13.1.2009, 19:55
Уважаемые, подскажите как унаследовать конструктор?

или как тут надо?
конструктор у наследника нужно написать примерно так:

Код

use base 'func';
sub new {
  shift->SUPER::new(@_);
}



Код

sub new {
    my $self = SUPER::new(@_);
    $self->{text} = 'some text';
    return $self;
}


но он не работает, пробовал по разному...

если даже и работает, то в пакете package child (в котором наследуем) все методы не видны (пишет что не извеный метод)

то что делаю:

это класс родитель: 

Код

package func;

use strict;
use CGI::Carp qw(fatalsToBrowser);
use DBI;

sub new {

my ( $self, %common ) = @_;
$self = {
se => undef,
session => undef,
he => undef,
p => undef,
query => undef
};

$self->{'se'} = $common{'se'} if $common{'se'};
$self->{'session'} = $common{'session'} if $common{'session'};
$self->{'he'} = $common{'he'} if $common{'he'};
$self->{p} = $common{p} if $common{p};
$self->{query} = $common{query} if $common{query};

# $self->{'passwd'} = $common{'passwd'} if $common{'passwd'};

if ( $common{passwd} ) {
$self = &md5crypt( $self, $common{'passwd'} );
}
bless $self;
return $self;
}



пытаюсь унаследовать: (то что не нужно - я вырезал)

Код

package child;

use strict;
use CGI::Carp qw(fatalsToBrowser);
use Data::Validate::Domain qw(is_domain);

use base 'func';

sub new {

# print "Child::new @_\n";
# my $self = shift;
# my ($data_p, $data_c)=@_;
# my $self = shift;
my ( %common ) = @_[1];

my $self->SUPER::new(@_[0]);
# $self->{child_data}=$data_c;
#return $self;


=sdf
my ( $self, %common ) = @_;
$self = {
se => undef,
session => undef,
he => undef,
p => undef,
query => undef
};

$self->{se} = $common{se} if $common{se};
$self->{session} = $common{session} if $common{session};
$self->{he} = $common{he} if $common{he};
$self->{p} = $common{p} if $common{p};
$self->{query} = $common{query} if $common{query};
bless $self;
$self->dbi_connect if $self->can("dbi_connect");
return $self;
=cut
}



примерно как это должно выглядеть в конструкторе где передаються не именнованные параметры (в данном случаен не знаю как применить это)
Код

#!/usr/bin/perl -w
use strict;
package Parent;
sub new {
print "Parent::new @_\n";
my $pkg=shift;
my $data=shift;
my $self={parent_data=>$data};
bless $self,$pkg;
}
sub echo {
my $self=shift;
print "$self->{parent_data}\n";
}
package Child;
use base 'Parent';
sub new {
print "Child::new @_\n";
my $pkg=shift;
my ($data_p, $data_c)=@_;
my $self=$pkg->SUPER::new($data_p);
$self->{child_data}=$data_c;
return $self;
}
sub echo {
my $self=shift;
print "$self->{child_data}\t";
$self->SUPER::echo;
}

package Main;
my $a=Parent->new("a_p");
my $b=Child->new("b_p","b_c");
use Data::Dumper;
print Dumper($a,$b);
$a->echo;
$b->echo;


Автор: ginnie 13.1.2009, 19:59
gcc, почему у Вас в func

Код

bless $self;


т.е. почему не указан класс? Кроме того, в child не должно быть

Код

bless $self;


P.S. Для создания конструктора класса-потомка мне нравится вариант

Код

sub new {
    my $self = SUPER::new(@_);
    $self->{text} = 'some text';
    return $self;
}

Автор: gcc 13.1.2009, 20:05
Цитата(ginnie @ 13.1.2009,  19:59)
gcc, почему у Вас в func

Код

bless $self;


так работает, по примеру, а как должно быть?

Автор: ginnie 13.1.2009, 20:07
gcc, например так

Код

sub new {
    my ( $class, %common ) = @_;
    my $self = {
        se => undef,
        session => undef,
        he => undef,
        p => undef,
        query => undef
    };

    $self->{'se'} = $common{'se'} if $common{'se'};
    $self->{'session'} = $common{'session'} if $common{'session'};
    $self->{'he'} = $common{'he'} if $common{'he'};
    $self->{p} = $common{p} if $common{p};
    $self->{query} = $common{query} if $common{query};
    
    # $self->{'passwd'} = $common{'passwd'} if $common{'passwd'};
    
    # Тут явно что-то не так
    #if ( $common{passwd} ) {
    #    $self = &md5crypt( $self, $common{'passwd'} );
    #}
    bless $self, $class;
    return $self;
}

Автор: gcc 13.1.2009, 20:07
Цитата(ginnie @ 13.1.2009,  19:59)
Кроме того, в child не должно быть

Код

bless $self;


там bless нету, там есть то что Вы подсказали
или еще то, что пробовал:
Код

sub new {
  shift->SUPER::new(@_);
}


Добавлено @ 20:08
ginnie,  сейчас попробую:

Код

    bless $self, $class;

Автор: ginnie 13.1.2009, 20:09
Судя по коду, Вы что-то не понимаете. Если что-то не понятно - надо спрашивать!

Автор: gcc 13.1.2009, 20:12
Цитата(ginnie @ 13.1.2009,  20:09)
Судя по коду, Вы что-то не понимаете. Если что-то не понятно - надо спрашивать!

если работает - значит правильно?  smile 

я нашел примеры и сделал так  как там, ну или добавил в конструктор еще, например, инициализацию подключения к DBI через can()... (мне там так удобно)

Автор: ginnie 13.1.2009, 20:17
gcc, как совместить Вашу мысль

Цитата(gcc @  13.1.2009,  20:12 Найти цитируемый пост)
если работает - значит правильно?


с

Цитата

но он не работает, пробовал по разному...

если даже и работает, то в пакете package child (в котором наследуем) все методы не видны (пишет что не извеный метод)



Автор: gcc 13.1.2009, 20:28
ginnie,  ну я имел ввиду что до этого

вот я изменил:

наследник:
Код

package child;

use strict;
use CGI::Carp qw(fatalsToBrowser);
use base 'func';

sub new {
    my $self = SUPER::new(@_);
    $self->{text} = 'some text';
    $self->dbi_connect if $self->can("dbi_connect");
    return $self;
}


в child ошибка
Код

Undefined subroutine &SUPER::new called at line 24.

на эту тсроку ругается
Код

    my $self = SUPER::new(@_);




родитель:
Код

package func;

use strict;
use CGI::Carp qw(fatalsToBrowser);
use DBI;

#use HTML::Template;
#use POSIX qw(ceil floor);

sub new {

    my ( $class, %common ) = @_;
    my $self = {
        se      => undef,
        session => undef,
        he      => undef,
        p       => undef,
        query   => undef
    };

    $self->{'se'}      = $common{'se'}      if $common{'se'};
    $self->{'session'} = $common{'session'} if $common{'session'};
    $self->{'he'}      = $common{'he'}      if $common{'he'};
    $self->{p}       = $common{p}       if $common{p};
    $self->{query}   = $common{query}   if $common{query};

    # $self->{'passwd'} = $common{'passwd'} if $common{'passwd'};

    if ( $common{passwd} ) {
        $self = &md5crypt( $self, $common{'passwd'} );
    }

bless $self, $class;

    return $self;
}


догадываюсь, что конструктор по другому надо построить?...

Автор: ginnie 13.1.2009, 20:39
gcc, в соответствии с http://perldoc.perl.org/perlobj.html вариант SUPER::new(@_) неправильный, поэтому попробуйте
Код

sub new {
    my $self = shift->SUPER::new(@_);
    $self->{text} = 'some text';
    $self->dbi_connect if $self->can("dbi_connect");
    return $self;
}


Автор: gcc 13.1.2009, 23:16
спасибо, заработало, я этот вариант тоже пробовал, но он не работал раньше...

возможно потому-что не было:
Код

    bless $self, $class;


сейчас вроде бы работает

Автор: ginnie 14.1.2009, 12:15
gcc, вариант

Код

bless $self;


делает $self объектом текущего класса, поэтому она неверно работает при вызове из дочернего класса, т.к. создает объект класса-родителя, а не потомка (поэтому недоступны методы класса-потомка). Вариант

Код

bless $self, $class;


создает объект того класса, который передается параметром (класса-потомка в нашем случае).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)