|
PERL'E DERSLERİ -
6
Sınıflar:
OOP türü yazdigimiz programlarda sadece nesneler vardir. Bu
nesneler, mesaj alisverisi yaparak, birbirleriyle haberlesirler.
Nesneler OOP de sinif olarak ifade edilen sablonlardan yaratilir.
Her sinif icinde, o siniftan üretilecek nesnelerin özelikleri,
davranislari tespit edilir. Örnegin Araba isminde bir sinif
yaratabiliriz. Bu siniftan üretilecek nesnelerin ortak yani, bir
motor, 4 teker, direksiyon gibi parcalar olacaktir.
Siniflar, nesne üretme yaninda baska bir özellige daha sahiptir.
Siniflar arasinda akraba ve is iliskileri kurmak mümkündür. Siniflar
hakkinda daha genis bilgiyi, bu bölümün ilerleryen satirlarinda
bulacaksiniz.
Nesneler:
OOP de nesneler siniflardan üretilir. Nesneler, siniflarin aksine
canlidir ve kimlikleri vardir. Ayni siniftan üretilmis iki nesnenin
sahip oldugu degiskenler degisik degerlere sahiptir. Örnegin araba
sinifindan üretilen Mercedes ve BMW marka iki arabanin plaka
numaralari degisiktir. Burada adi gecen plaka numarasi, sinif icinde
yer alan bir özelliktir. Siniftan üretilen her nesne bu özelligi
alir. Nesneler üretilirken, nesne özellikleri, sahip olduklari
yapiya göre, degisik olacaktir. Araba örneginde oldugu gibi,
Mercedes ve BMW nesneleri degisk plaka numaralarina sahiptir.
Yazilan OOP programlarda sadece nesneler ve aralarindaki
interaksiyon söz konusudur
Metodlar:
Metodlar bir nesnenin dis dünyaya acilan kapilaridir. Bir nesnenin
icinde ne oldugu, nesnenin nasil calistigi disaridan görünmez.
Nesnenin sahip oldugu bir ic dünyasi vardir. Eger nesne ile
interaksiyona girmek istiyorsak, disa acilan kapilarindan (metodlardan)
birini kullanmamiz gerekir. Nesnelere, sinif icinde tanimlanmis ve
her nesnenin sahip oldugu metodlar araciligiyla mesaj
gönderebiliriz. Eger bir nesneden birsey yapmasini bekliyorsak,
metodunu kullanarak, ona bir mesaj göndeririz. Nesne bu mesaji
alarak, gerekli islemi yapar.
Metodlar nesnelerin dis dünyaya karsi davranislarini tanimlar.
Metodlari, diger programlama dillerinde kullanilan fonksiyonlar
olarak düsünebiliriz. Nesneler ile sadece bu metodlari kullanarak,
interaksiyona girebiliriz.
Konstruktör:
Nesnelerin siniflardan yapildigini daha önce ögrendik. Nesneler
üretilirken, sahip olduklari degiskenlerin degisik degerlerde olmasi
gerekir. Araba örneginde oldugu gibi, Mercedes ve BMW marka iki
nesnenin degisik plaka numaralarina sahip olmalari gerekir. Bu demek
oluyor ki, nesneler üretiliken, onlara degisik kimlikler verecek bir
mekanizmaya ihtiyacamiz var.
Bu görevi sinif icinde konstruktörler üstlenir. Nesneler
konstruktörler araciligiyla üretilir. Konstruktör bir nesne
üretmeden önce, nesne icin gerekli degisken degerleri belirlenir ve
bu degerler parametre olarak konstruktöre gönderilir. Kontsruktör bu
degerleri kullanarak, nesneyi üretir. Her sinif icinde, nesne
üretmek icin bir kontruktör vardir.
Destruktör:
Her sinif icinde kontruktör yaninda birde destruktör bulunur.
Destruktörün görevi hayati sona ermis bir nesneyi sistem üzerinden
uzaklastirmaktir. Program bitiminde üretilen bütün nesneler
destruktör araciligiyla yok edilir.
Miras:
OOP nin en büyük özelliklerinden birisi, siniflar arasindan miras
birakma teknigiyle, yazilan kodun, defalarca baska bölümlerde
kullanilabilmesidir.
Nesneler siniflardan üretilir. Tasit isminde bir sinifimiz oldugunu
düsünün. Bu siniftan motorlu tasitlar ve motorsuz tasirlar isminde
iki alt-sinif üretmemiz mümkündür. Bu üretilen iki alt sinif, tasit
isimli sinifta olan tüm nesne metod ve degiskenleri miras olarak
alirlar. Alt siniflardan bir gram kod eklemeden, nesneler
üterebiliriz Alt siniflarda gerekli degisiklikleri yaparak, bu
sinifin nesnelerini özellestirebiliriz. Örnegin motorlu tasit
sinifina, beygirgücü isminde bir degisken ekleyebilriz. Bu alt
siniftan üretilecek bir nesne, tasit isimli sinifta olan tüm metod
ve degiskenleri miras olarak aldigi gibi, ayrica beygirgücü isminde
yeni bir degiskene daha sahip olacaktir.
Gördügümüz gibi, miras birakma teknigi ile, bir kere yazilan kod,
defalarca kullanilabilir. Miras (inheritance) teknigi bunu mümkün
kiliyor. Miras birakmanin ve almamini nasil kullanildigini, asagida
yer alan örnegimizde görecegiz.
C++ ve Java dillerinde oldugu gibi, Perl dilinde OOP tarzi
programlar yazmak mümkündür. Perl dilinde OOP tarzi programlarin
nasil yazildigini incelemeden, C++ dilinde bir programi inceleyelim.
OOP terimlerini bu örnek üzerinde göstermek istiyorum. Daha sonra bu
programin Perl dilinde nasil yazilacagini görecegiz.
Yazacagimiz örnekte Araba isimli bir sinif yer alacak. Miras birakma
teknigini kullanarak, Mercedes ve BMW isimlerinde iki alt-sinif
üretecegiz. Bu altsiniflara, Araba anasinifinda yer alan tüm metod
ve degiskenlerin miras kalmasi yaninda, altsiniflar, kendileri icin
gerekli degiskenleri de tanimlayacaklar.
Bu C++ örnegini MS Visual C++ 6.0 programi ile derledim. Programi
derlemek icin herhangi bir C++ derleyicini kullanabilirsiniz.
Program asagida yer alan dosyalar icinde yer alacak:
" Araba sinifi deklarasyonu, Araba.h,
" Araba sinifi definisyonu, Araba.cpp
" Mercedes altsinifi deklarasyonu, Mercedes.h,
" Mercedes altsinifi definisyonu, Mercedes.cpp,
" BMW altsinifi deklarasyonu, BMW.h,
" BMW altsinifi definisyonu, BMW.cpp,
" Ana program main.cpp
// Araba.h - Araba sinif deklarasyonu
class Araba
{
public: Araba();
void print();
Araba(char*, int);
~Araba();
protected:
int beygirgucu;
char* plakano;
};
Class direktifi ile bir sinif tanimlanir. Public bölümünde, sinif
icinde yer alacak ve sonra üretilen nesneler tarafindan kullanilcak
metodlar yer alir. Nesneleri üretmek icin Araba(char*, int)
kontruktörü kullanilir. Konsruktöre bir string ve integer parametre
olarak gönderilir. Bunun ne anlama geldigini daha sonra görecegiz.
Protected bölümü icinde, nesnelerin sahip olacaklari degiskenler yer
alir. Protected ve Private sayesinde, bu degiskenler, disaridan
gelebilecek saldirilara karsi korunur. Bu degiskenler sadece sinif
metodlari kullanilarak degistirilebilir. OOP de nesnelerin ic
hayatlarinin korunmasi önemli bir prensiptir. Hicbir sekilde,
nesnenin sahip oldugu degerler disardan degistirilememelidir. Bu
islem, metodlar arciligiyla nesneye mesaj gönderilerek yapilabilir.
Araba sinifinin beygirgucu ve plakano isminde iki degiskeni vardir.
Buna göre, bu siniftan üretilen her nesne yukarda yer alan metod ve
degiskenlere sahip olacaktir. Konstruktör kullanilarak, her nesneye
baska bir baslangi degeri verilir. Bu sadeye üretilen her nesne
baska bilgileri tasir.
// Araba.cpp - Araba sinif definisyonu
#include <iostream.h>
#include "Araba.h"
// Konstruktör
Araba::Araba(char* plaka, int ps)
{
plakano=plaka;
beygirgucu=ps;
}
//Destruktör
Araba::~Araba() { }
//Print metodu
void Araba::print()
{
cout<<"Plaka:"<< plakano<<"Beygirgucu:"<<beygirgucu;
// Standart kontruktör
Araba::Araba()
{
beygirgucu=0;
plakano=0;
}
Araba.cpp dosyasinda sinifin metodlari yazilir. Araba::Araba(char*
plaka, int ps) seklinde kontruktörü tanimliyoruz. Bu konstruktörü
kullanarak, üretecegimiz nesnelere baslangic degerleri verecegiz.
// Mercedes.h - Mercedes sinif deklarasyonu
#include "Araba.h"
class Mercedes : public Araba
{
public:
void print();
Mercedes(char*, char*, int);
~Mercedes();
private:
char* model;
};
Araba sinifindan, class Mercedes : public Araba tanimlamasini
kullanarak, Mercedes isminde bir altsinif olusturuyoruz. Bu andan
itibare, Mercedes sinifi, Araba sinifinin tüm özellikleri alir.
Araba ve Mercedes siniflari arasinda baglanti kurabilimek icin #include
"Araba.h" direktifiyle, Araba.h dosyayini Mercedes.h dosyayina
ekliyoruz.
Mercedes(char*, char*, int); konstruktörü ile, Mercedes Marka
arabalari üretecegiz. Araba konstruktörünün aksine bu kontruktör üc
parametre aliyor. Mercedes marka bir araba ürettigimizde, plakano ve
beygirgücü degiskenleri yaninda, Mercedes konstruktörüne model
degiskeninide parametre olarak, gönderecegiz. Gördügünüz gibi,
Mercedes, Araba'nin alt sifini oldugundan, Mercedes sinifi icinde
plakano ve beygirgucu degiskenlerini kolayca kullanabiliyoruz.
// Mercedes.cpp - Mercedes sinif definisyonu
// Konstruktör
Mercedes::Mercedes(char* mod, char* plaka, int ps) :Araba(plaka,ps)
{
model=mod;
}
// Destruktör
Mercedes::~Mercedes() { }
// Araba sinifindan aldigimiz ve redefine ettiginiz Print metodu
void Mercedes::print()
{
cout<<"Model:"<<model;
Araba::print();
}
Mercedes.cpp dosyasi icinde dikaktinizi ceken satir
Mercedes::Mercedes(char* mod, char* plaka, int ps) :Araba(plaka,ps)
olmustur. Mercedes marka bir araba üretebilmek icin model, plakano
ve beygirgucu degiskenlerini parametre olarak Mercedes Kontruktörüne
gönderiyoruz. Arabamiz bu degerlerle üretilecektir.
Peki :Araba(plaka,ps) ne anlama geliyor?
Altsiniflardan üretilen her nesne icinde, ana siniftan üretilmis bir
nesne yer alir. Altsinif icinde kod eklemesi yapmadan, ana sinifta
yer alan metod ve degiskenleri kullanmamiz, nesne icinde yer alan,
anasinifi nesnesi üzerinden olur. Nesneler üretilirken,
konstruktörler aracigiyla istenen baslangic degerleri tespit edilir.
Her sinif icinde bir standart konstruktör vardir. Alt siniftan bir
nesne ürettigimizde, bu nesne icinde yer alacak anasinif
nesnesininde bir baslangic degerine sahip olmasi gerekir. Bunu :
:Araba(plaka,ps) seklinde bir tanimlamayla yapabiliriz. Mercedes
nesnesi icin model, plakano ve beygirgucu parametrelerini alarak,
baslangic degerlerini belirliyoruz. Model degiskeni Mercedes icinde
yer aldigi icin, esleme bu sinif icinde yapiliyor. Diger iki
parametre, ana sinif icinde bulunan degiskenlere eslenmesi gerektigi
icin, Araba(plaka, ps) seklinde anasinif konstruktörüne gönderilir.
Ana sinif bu parametreleri alarak, degiskenlere gerekli baslangic
degelerini verecektir. Böylece Mercedes nesnesi gecerli baslangic
degerlerine sahip olacaktir.
Nesneler, anasiniftan miras kalan tüm metod ve degiskenleri
kullanabilirler. Isteyen altsiniflar, anasiniftan aldiklari metodlar
üzerinde degisklik yapabilirler. Yukardaki örnekte, Mercedes sinifi,
anasinif icinde tanimlanmis print() metodunu alarak, model
degiskeninin degerini ekrana basmak icin degistirmistir. Araba::print();
komutuyla, anasinif icinde tanimlanan print() fonksiyonu
calistirilir. Bu fonsiyon plakano ve beygirgucu degiskenlerinin
degerini ekrana basar. Mercedes sinifinda, miras kalan print()
fonksiyonu genisletilerek, plakano ve beygirgucu degiskenleri
yaninda model degiskeninin degeride ekrana basilmis olur.
PERL'E DERSLERİ -
7
// BMW.h - BMW sinif
deklarasyonu
#include "Araba.h"
class BMW : public Araba
{
public: BMW(char*, int);
~BMW();
};
// BMW.cpp - BMW sinif definisyonu
// Konstruktör
BMW::BMW(char* x, int y):Araba(x,y)
{ }
// Destruktör BMW::~BMW() { }
BWM sinifi icin gerekli tanimlari yaptikran sonra, ana programimizi
yazabiliriz.
//main.cpp
#include <iostream.h>
#include "Araba.h"
#include "Mercedes.h"
#include "BMW.h"
void main(void)
{
Mercedes m1("E-200","34-MSB-24",90);
BMW b1("34-FO-060",150);
m1.print();
b1.print();
}
#include direktifi ile, ana- ve altsinif kodlari ana programa
eklenir. Mercedes m1("E-200","35-AH-119",90); komutu ile m1 isminde
Mercedes sinifindan bir nesne ürettik. Parantez icinde, Mercedes
sinifinin kontruktörüne gönderilmek üzere parametreler yer aliyor.
Nesnenin sahip oldugu degiskenleri ve degerlerini ekrana basmak icin
print() fonksiyonunu kullanacagiz. print() fonksiyonu, Mercedes
altsinifina Araba sinifindan miras kalmisti. m1.print(); komutu ile
m1 isimli nesneye mesaj göndererek, print() fonksiyonunu
calistirmasini söylüyoruz.
Ekran cikisi:
Model: E-200 Plaka: 34-MSB-24 Beygirgucu: 90
Print() metodunu Mercedes altsinifinda degistirdigimiz icin, model
degiskeninin degeri de digerlerinin yanida ekrana basilir. Eger
Mercedes sinifinda print() isminde bir fonksiyon tanimlamamis
olsaydik, nesne, anasinif icinde yer alan print() fonsiyonunu
calistiracakti ve ekran cikisi söyle olacakti:
Plaka: 34-MSB-24 Beygirgucu: 90
Ana sinifta yer alan print() fonsiyonunun, Mercedes sinifinda
yeralan model degiskeninden haberi olmadigi icin, sadece plakano ve
beygirgucu degiskenlerini ekrana basar. Gercektende ana siniflar,
altsiniflarinda hangi metodlarin ve degiskenlerin yer aldigini
bilmezler. Bunun aksine, alt siniflar, anasinifta yer alan tüm metod
ve degiskenleri tanirlar.
OOP yi ve kullanilan terimleri tanidiktan sonra, bu örnegi Perl
dilinde yazalim.
#!/usr/bin/Perl
use strict;
print "Content-type: text/html\n\n";
######### Class Araba######
package Araba;
sub araba
{
my $class=shift;
my $this={};
$this->{'plakano'}=shift;
$this->{'beygirgucu'}=shift;
bless($this, $class);
}
Perl'de siniflar paket (package) olarak tanimlanir. C++ örneginde
oldugu gibi, sinif isminde bir konstruktör tanimliyoruz. shift, bir
subrutine gönderilen parametrelere sirayla ulasabiliriz. Yeni bir
nesne üremek icin araba() kontruktörü calistirildiginda, shift
üzerinden sirasiyla ulasabilecegimiz bilgiler: sinifismi, plakano ve
beygirgücüdür.
Önce shift icinde bulunan ilk bilgi (sinif ismi) $class degiskenine
esitlenir. $class degiskeni yardimiyla, üretilecek nesnenin hangi
siniftan oldugu tespit edilir. $this, C++ dilinde de kullanilan bir
referanstir. Perl de nesnelere referanslar üzerinden ulasilir.
Nesnenin sahip oldugu degisken degelerini yerlestirmek icin hash
tipi bir liste kullanilir. bless fonksiyonu ile nesne canlanir.
sub print
{
my $this=shift;
print "$this->{'plakano'}\n";
print "$this->{'beygirgucu'}\n";
}
print() subrutini nesne degiskenlerinin degerini ekrana basar.
Herhangi bir nesne tarafindan bu metod cagrilidiginda, metoda, shift
üzerinden nesne kimligi gönderilir. Bu kimligi $this referansina
esitleyerek, subrutin icinde nesne icin gerekli islemleri
yapabiliriz.
print "$this->{'plakano'}\n"; ile nesnenin sahip oldugu $plakano
isimli degiskenin degeri ekrana basilir. Daha öncede belirttigim
gibi, bir nesnenin tüm degisken ve degerleri hash tipi bir listede
saklanir. Bu liste araba() konstruktörü tarafindan yaratilir. $this
üzerinden nesnenin sahip oldugu tüm degiskenlere ulasabiliriz. ;
sub DESTROY
{
print "Nesnenin hayati son buldu.";
}
Program bitimiyle tüm nesnelerin hayatina son verilir. Nesnenin
yasamina son verilmeden önce, DESTROY metodu cagrilir. DESTROY sinif
icinde destruktör vazifesi görür.
###### Class Mercedes #######
package Mercedes;
use vars qw(@ISA);
@ISA=qw(Araba);
Perl dilinde altsiniflara miras birakma islemi @ISA listesi
üzerinden gerceklesir. @ISA icinde tüm üstsiniflar tanimlanir. Bu
konuyu detayli olarak ilerleyen satirlarda inceleyecegiz.
# Kontruktör
sub mercedes
{
my $class=shift;
my $model=shift;
my $plaka=shift;
my $ps=shift;
my $this=Araba->araba($plaka,$ps);
$this->{'model'}=$model;
bless($this, $class);
}
sub print
{
my $this=shift;
print "$this->{'model'}\n";
print "$this->{'plakano'}\n";
print "$this->{'beygirgucu'}\n";
}
Mercedes sinifini Araba sinifinin altsinifi olarak tanimliyoruz.
Mercedes @ISA listesin üzerinden bütün Araba metod ve degiskenlerine
ulasabilir. Simdi ana programi yazalim:
package main;
my $b1=Mercedes->mercedes("E-200","34-MSB-24",95);
$b1->print();
Ana program yazmak icin main isminde bir paket tanimlamamiz
gerekiyor. Daha sonra Mercedes sinifinda yer alan mercedes
konstruktörünü kullanarak, $b1 isminde bir nesne olusturuyoruz. $b1
bir referanstir. Bu referansi kullanarak, print() metodunu
cagiriyoruz.
Program icinde dikkatinizi cekmis olabilecek birkac noktaya deginmek
isiyorum:
* C++ aksine, Perl dilinde konstruktörler derleyici tarafinda
otomatik olarak calistirilmaz. C++ dilinde, sinif isminde bir
konstruktörün tanimlanmis olmasi gerekir. Perl de böyle bir
zorunluluk yok. Konstruktör herhangi bir isimde olabilir. Nesneleri
olusturmak icin konstruktörü calistirmaniz gerekir.
* Nesneleri yok etmek icin destruktörü calistirmaniz gerekmez. Bu
islemi paketin sahip oldugu destruktör otomatik olarak yapar.
* Bir sinifin metodlarina degisik sekilde parametre girisi yapilir.
Örnegin konstruktörler parametre olarak önce sinif ismini alirlar.
Normal sinif metodlarina önce nesneye ait $this referansi
gönderilir.
* Siniflar arasi miras birakma ve alma @ISA listesi üzerinden
gerceklesir. Bu liste icinde tüm ana siniflar yer alir.
* C++ dilinde yer alan public, private, protected koruma
mekanizmalari Perl dilinde yoktur.
* Sinif tanimlamak icin kullanilan class gibi özel bir kelime
yoktur.
* Metodlar sinif icinde tanimlanir. Sinif icinde kullanilan
degiskenlere, hash tipi bir liste üzerinden ulasilabilir. Üretilen
her nesnenin, degiskenlerini ve degerlerini sakladigi hash tipi bir
listesi vardir.
* Nesneler Perl'de hangi sinifi ait oldugunu bilen referanslardir.
Nesne hangi sinifa ait oldugunu bless() fonksiyonu araciligiyla
ögrenir. Her konstruktörün en son satirinda bless() fonksiyonu yer
alir.
|