Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org
 

Создание классов и объектов

Класс — это пакет с набором методов . Метод — это подпрограмма, встроенная в класс или объект. Метод использует ссылку на объект или имя класса, передаваемое ему в качестве первого аргумента. Объект — это ссылка на элемент данных. В отличие от других ссылок, этот элемент знает, к какому классу он относится. Рассмотрим пример класса Class1, для которого определен конструктор new. В этом конструкторе создается ссылка на анонимный хеш, который будет хранить данные объекта. package Class1; sub new { my $self = {}; bless($self); return $self; } return 1; Для создания объекта вызывается конструктор, который обычно имеет имя new. В следующем примере мы создаем объект определенного раннее класса Class1: use Class1; my $object = Class1->new(); Есть два типа методов: методы класса и методы объекта (методы экземпляров класса). Метод класса вызывается с помощью имени класса, а метод экземпляра класса — с помощью объекта (ссылки). package Class1; sub new { my $self = {}; bless($self); return $self; } sub name { my $class = shift; print "This is the class method.\n"; return $class; } return 1; use Class1 $classname = Class1->name(); $classname = Class1::name("Class1"); В следующем примере создается метод объекта data. Первый аргумент, передаваемый методу — это ссылка на сам объект. Мы используем ее, чтобы сохранить данные в анонимном хеше package Class1; sub new { my $self = {}; bless($self); return $self; } sub data { my $self = shift; if (@_) {$self->{DATA} = shift;} return $self->{DATA}; } return 1; use Class1 my $object1 = Class1->new(); $object1->data("Hello!"); print "Here is the text in the object: ", $object1->data(); Here is the text in the object: Hello! Хотя многие объектно-ориентированные языки программирования поддерживают приватные методы и переменные, (то есть, внутренние методы и переменные, недостижимые вне класса или объекта), Perl не позволяет делать этого явно. В следующем примере, мы отслеживаем полное число объектов, созданных для конкретного класса, запоминая его в переменной класса $total package Cdata; my $total = 0; sub new { $self = {}; $total++; return bless $self; } sub gettotal {return $total;} return 1; use Cdata; $object1 = Cdata->new; print "Current number of objects: ",$object1->gettotal, "\n"; $object2 = Cdata->new; print "Current number of objects: ", $object2->gettotal, "\n"; $object3 = Cdata->new; print "Current number of objects: ", $object3->gettotal, "\n"; Current number of objects: 1 Current number of objects: 2 Current number of objects: 3 Для выполнения команд Perl, связанных с уничтожением объектов, можно использовать деструкторы, — точнее, они начинают работать, когда объект готов к уничтожению. В Perl работает автоматическая система сборки мусора. Она уничтожает элементы и освобождает занимаемую ими память, когда они больше не нужны, — например, когда потеряна ссылка на данные, переменная выходит за границы области видимости, либо интерпретатор прекращает работу. В отличие от конструкторов, для деструкторов Perl имеется вполне определенное имя DESTROY: package Class1; sub new { my $type = {}; bless($self); return $self; } sub DESTROY { print "Object is being destroyed!\n"; } return 1; Наследование : В следующем примере от базового класса Class1 порождается дочерний Class2. В отличие от других объектно-ориентированных языков программирования, в Perl нельзя объявить члены класса как private или как protected package Class1; sub new { my $self = {}; bless($self); return $self; } sub gettext {return "Hello!\n";} return 1; package Class2; use Class1; @ISA = qw/Class1/; sub new { my $self = {}; bless($self); return $self; } return 1; use Class2; my $object1 = Class2->new(); print "The object says: ", $object1->gettext; The object says: Hello! Perl не проверяет структуру данных, создаваемую в конструкторе данного класса, даже на минимальную совместимость с методами, которые наследуются от родительских классов. Совместимость данных и методов — целиком на совести программиста. В этом примере конструктор класса Class2 можно унаследовать из класса Class1 (поскольку код Perl для этих конструкторов совпадает), но так как конструктор класса Class1 и возвращает объект класса Class1, а не класса Class2, это вызвало бы проблемы. Чтобы конструктор класса Class1 возвращал объекты класса Class2 (или любого другого, для которого Class1 является базовым), при работе с ним в контексте дочернего класса, его необходимо переписать. Для этой цели мы используем специальную форму функции bless с двумя аргументами, с которой мы еще не сталкивались. package Class1; sub new { my $class = shift; my $self = {}; $self->{NAME} = "Christine"; bless $self, $class; return $self; } return 1; package Class2; use Class1; @ISA = qw/Class1/; sub new { my $class = shift; my $self = {}; $self->{DATA} = 200; bless $self, $class; return $self; } return 1; use Class2; my $object1 = Class2->new(); print $object1->{NAME}, " has \$", $object1->{DATA}, "\n"; Christine has $200 В Perl вопрос о том, является ли метод виртуальным или нет, решается просто: все методы, вызываемые как методы классов, являются статическими. Наоборот, все методы, вызываемые как методы объектов, являются виртуальными. Тем самым свойство «виртуальности» зависит от способа вызова, и один и тот же метод может быть как виртуальным, так и статическим. Пример: package Class1; sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } sub gettext{ return "Hello!\n"; } sub printA { my $self = shift; print $self->gettext; # виртуальный вызов } sub printZ { my $self = shift; print Class1->gettext; # статический вызов } return 1; package Class2; # конструктор наследуется use Class1; @ISA = qw/Class1/; sub gettext{ # замещение метода return "Bye..."; } return 1; Использование : use Class1; use Class2; $object1 = Class1->new(); $object2 = Class2->new(); # статический вызов замещенного метода $object1->printZ; $object2->printZ; # виртуальный вызов замещенного метода $object1->printA; $object2->printA; Hello! Hello! Hello! Bye... Тот факт, что методы Perl, вызываемые как методы объекта, ведут себя как виртуальные методы традиционных языков программирования, позволяет нам еще больше усовершенствовать схему конструкторов (см. выше раздел «Наследование конструкторов»). А именно, разобьем конструктор на две части: метод new, который выделяет память под объект (анонимный хеш, анонимный массив или, даже, анонимный скаляр) и привязывает ссылку к классу, и init, который инициализирует выделенную память. Тогда мы можем замещать в дочерних классах только инициализирующую часть init, оставляя конструктор неизменным. Рассмотрим пример: package Class1; sub new { my $class = shift; my $self = {}; bless $self, $class; $self->init(@_); return $self; } sub init { my $self = shift; $self->{DATA} = shift; return $self; } return 1; package Class2; # конструктор new наследуется use Class1; @ISA = qw/Class1/; sub init { my $self = shift; $self->{DATA} = shift; $self->{VALUE} = shift; return $self; } return 1; use Class1; use Class2; $object1 = Class1->new(1024); $object2 = Class2->new(1024, 3.141592653589); В Perl можно создавать переменные класса, — то есть, переменные, недоступные вне класса, и содержащие значения, общие для всех объектов класса и доступные им. К сожалению, в Perl нет возможности организовать автоматическое наследование переменных класса, если только вы не организуете доступ к переменным базового класса с помощью наследуемых методов доступа. Единственный способ справиться с этой проблемой — это использовать для доступа к переменным класса только методы доступа (то есть, никогда не обращаться к ним напрямую), и при создании дочернего класса вручную повторить в его теле как переменные класса, так и методы доступа к ним. При этом в силу того, что методы объекта в Perl считаются виртуальными, новые переменные класса будут использоваться независимо от того, работает с ними метод дочернего или же метод, унаследованный от базового класса: package Class1; my $counter = 1; sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } sub getcounter{ return $counter; } sub setcounter{ $counter = shift; return $counter; } sub twicecounter{ # косвенный доступ my $self = shift; $my temp = $self->getcounter; $temp = 2*$temp; $self->setcounter($temp); return $temp; } return 1; package Class2; # конструктор наследуется my $counter = 100; use Class1; @ISA = qw/Class1/; sub getcounter{ return $counter; } sub setcounter{ $counter = shift; return $counter; } sub triplecounter{ # косвенный доступ my $self = shift; $my temp = $self->getcounter; $temp = 3*$temp; $self->setcounter($temp); return $temp; } return 1; use Class2; $object = Class2->new(); print $object->twicecounter, "\n"; print $object->triplecounter, "\n"; 200 300 В Perl производный класс может наследовать сразу от нескольких классов. Каждый из них должен быть объявлен с помощью команды use и перечислен в массиве @ISA. package Class0; sub printhi {print "Hi\n";} return 1; package Class1; sub printhello {print "Hello\n";} return 1; package Class1; use Class0; use Class1; $ISA = qw/Class0 Class1/; sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } return 1; use Class2; my $object = Class2->new(); $object->printhi; $object->printhello; Hi Hello
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
Vourhey
  Good. Thanks
2008-04-18 11:45:01