Üye Giriş

Tavsiye Programlar

Firefox 2

Alexa Tolbar
SANAL BİTİŞ FONKSİYONLARI PDF Yazdır E-posta
Yazar Hanzala   
Sunday, 26 December 2004

Sanal Bitiş Fonksiyonları(virtual destructor)

    Bir sınıfın bitiş fonksiyonu sanal olabilir. Aslında ne zaman bir türetme yapılacaksa taban sınıfın bitiş fonksiyonu sanal yapılmalıdır. Taban sınıfın bitiş fonksiyonu sanal yapılırsa o sınıftan türetilen tüm sınıfların bitiş fonksiyonları otomatik olarak sanal kabul edilir. Normal olarak delete operatörünün operandı hangi sınıfa ilişkin bir adres ise o sınıfa ilişkin bitiş fonksiyonu çağırılır. Ancak bazı durumlarda adrese ilişkin sınıfın bitiş fonksiyonu değil de nesnenin orijinaline ilişkin sınıfın bitiş fonksiyonunun çağırılması gerekir.

 




B sınıfı A sınıfından türetilmiş olsun;

{
    A *p;

    p = new B(n);
    delete p;
}

Burada normal olarak p göstericisi A sınıfına ilişkin olduğu için delete p; işlemindeA sınıfının bitişi fonksiyonu çağırılır. Oysa B sınıfına ilişkin bitiş fonksiyonunun çağırılması uygun olan durumdur. İşte taban sınıf bitiş fonksiyonu sanal yapılırsa B sınıfına ilişkin bitiş fonksiyonu çağırılır. Bu bitiş fonksiyonu kendi içerisinde zaten A sınıfının bitiş fonksiyonunu da çağıracaktır. Bir sınıf kendisinden türetme yapılacak şekilde tasarlanıyorsa mutlaka bitiş fonksiyonu sanal yapılmalıdır.

iostream Sınıf Sistemi

    Bu sınıf sistemi ekran, klavye ve dosya işlemleri için türetilmiş bir dizi sınıftan oluşur.

 


istream sınıfı klavye ve dosyadan okuma yapmak için gereken veri elemanlarına ve üye fonksiyolarına sahiptir. ostream sınıfı ise ekrana ve dosyaya bilgi yazmak için gereken veri elemanlarına ve üye fonksiyonlarına sahiptir. ios sınıfı okuma ve yazma işlemlerinde kullanılan temel ve ortak veri elemanlarını ve üye fonksiyonlarını bulunduran bir sınıftır. ostream sınıfının her türden parametreye sahip bir grup << (sola shift) operatör fonksiyonu vardır. Bu operatör fonksiyonları parametreleri ile belirtileni ekrana yazdırırlar. Yani ostream sınıfı türünden bir sınıf nesnesi tanımlanır ve bu operatör fonksiyonları kullanılırsa ekrana yazdırma yapılabilir.

ostream x;
x << 100;

Ancak zaten kütüphane içerisinde cout isimli bir nesne tanımlanmıştır. Yani bu nesne kullanılarak ekrana yazdırma yapılabilir. iostream sınıf sisteminin bütün bildirimler iostream.h içerisindedir. Sınıfların üye fonksiyonları kütüphane içerisindedir.

    ostream sınıfının << operatör fonksiyonlarının geri dönüş değerleri yine ostream türünden bir referanstır. Böylece bu operatör fonksiyonu birden fazla eleman için kombine edilebilir.

/*-----cout.cpp-----*/
#include <iostream.h>

void main(void)
{
int a = 123;

cout << "Value=" << 20 << '\n';
}
/*-------------------*/

Sınıf İçerisinde Başka Bir Sınıf, Yapı, typedef ve enum Bildirimlerinin Bulunması

    Bir sınıfın içerisinde yapı, başka bir sınıf, enum vs. bildirimleri yapılabilir. Genel olarak sınıf içerisinde bildirilen bütün değişken isimleri(yapı, sınıf, enum sabitleri gibi) dışarıdan ancak çözünürlük operatörü kullanılarak sınıf ismiyle erişilebilir. Tabii bu erişimin geçerli olabilmesi için bildirimin sınıfın public bölümde yapılmış olması gerekir. Yani sınıf içerisinde bildirilen bütün değişkenler sınıf faaliyet alanına sahip olur. Sınıfın üye fonksiyonları içerisinde doğrudan, dışarıdan ancak sınıf ismi ve çözünürlük operatörüyle çağırılabilir.

class X {
    private:
        int x;
    public:
        typedef unsigned int WORD;
        void func(void);
};

void X::fonk(void)
{
    WORD x;     /*Doğru*/
}

void main(void)
{
    WORD x;    /*Yanlış*/
    X::WORD x;    /*Doğru*/
}

iostream Sınıf Sisteminde Formatlı Yazdırma İşlemleri

    ios sınıfının protected bölümünde long bir x_flags isimli bir değişken vardır. ostream sınıfının << operatör fonksiyonları x_flags değişkeninin bitlerine bakarak yazdırma işleminin nasıl yapılacağını anlarlar. Bu değişkenin değerini alan ve değişkenin değerini değiştiren iki public üye fonksiyonu vardır:

long flags();
long flags(long);

x_flags değişkeninin ilgili bitlerini set edebilmek için ios sınıfı içerisinde bütün bitleri 0 yalnızca bir biti 1 olan çeşitli sembolik sabitler enum sabiti biçiminde tanımlanmıştır. Örneğin bitlerden birisi yazma işleminin hex sistemde yapılıp yapılmayacağını belirler. O bitin set edilip eski hale getirilmesi şöyle yapılabilir.

#include <iostream.h>

void main(void)
{
    long x;
    x = cout.flags();
    cout.flags(x | ios::hex);         /*hex biçimde yazılmasını sağlar*/
    cout.flags(x & ~ios::hex);    /*hex biçimde yazılmamasını sağlar*/
}

x_flags değişkeninin uygun bitleri 1 yapılarak yazdırma işlemi çeşitli biçimlere çekilebilir.

/*-----cout2.cpp-----*/
#include <iostream.h>

void main(void)
{
int a = 100;
long x;

cout << a << '\n';
x = cout.flags();
cout.flags(x & ~ios::hex | ios::hex);
cout << a << '\n';
}
/*--------------------*/

Burada yapılan işlemi tek aşamada yapan setf isimli bir üye fonksiyon da vardır.

long setf(long);
long unsetf(long);

setf fonksiyonu önce x_flags içerisindeki değeri alır, bunu parametresiyle or işlemine sokarak işlemi bir hamlede gerçekleştirir.

/*-----cout3.cpp-----*/
#include <iostream.h>

void main(void)
{
int a = 100;

cout << a << '\n';
cout.setf(ios::hex);
cout << a << '\n';
cout.unsetf(ios::hex);
cout << a << '\n';
}
/*--------------------*/

ios sınıfının protected x_width elemanı yazma işlemi için kaç karakter alanı kullanılacağını belirlemekte kullanılır. Bu elemanla ilişki kuran iki fonksiyon vardır.

int width(void);
int width(int w);

Benzer biçimde x_precision noktadan sonra kaç basamak yazılacağını belirlemekte kullanılır.

/*-----cout4.cpp-----*/
#include <iostream.h>

void main(void)
{
double x = 3.52534;

cout << x << '\n';
cout.precision(10);
cout << x << '\n';
}
/*--------------------*/

Template Fonksiyonlar

    Genel biçim:
template <class(typename) T> [geri dönüş değeri] <fonksiyon ismi>([parametreler])
{

}

Örnek:
template <class T>
void fonk(T a)
{

}

template bir anahtar sözcüktür. template anahtar sözcüğünden sonra < > gelmelidir. < > arasındaki class anahtar sözcüğünün normal sınıf işlemleriyle hiçbir ilgilisi yoktur. class anahtra sözcüğü yerine 1996 standardizasyonunda typename anahtar sözcüğü de kullanılabilir. class anahtar sözcüğünden sonra isimlendirme kuralına göre herhangi bir isim yazılır. Bu isim bir tür belirtir. Template fonksiyonlar ve sınıflar birer şablondur. Yani kendi başlarına kodda yer kaplamazlar. Bir template fonksiyon çağırıldığında derleyici önce çağırılma ifadesindeki parametre yapısını inceler. Bu türe uygun olarak şablonda belirtilen fonksiyondan programcı için yazar.

/*-----templat.cpp-----*/
#include <iostream.h>

template <class T>
void fonk(T a)
{
cout << a << endl;
}

void main(void)
{
fonk(3.5);
fonk(30L);
fonk(40L);
}
/*----------------------*/

Template fonksiyonlarda tür belirten sözcüğe template argümanı denir. Template argümanının template fonksiyon parametre yapısı içerisinde gözükmesi zorunludur. Zaten gözükmemesi durumu da anlamsız olur. Bu template argümanı geri dönüş değeri olarak ya da fonksiyon içerisinde tür belirten sözcük olarak kullanılabilir.

/*-----templat2.cpp-----*/
#include <iostream.h>

template <class T>
T abs(T a)
{
return a > 0 ? a : -a;
}

void main(void)
{
cout << abs(-3.5) << endl;
cout << abs(-3) << endl;
cout << abs(-10L) << endl;
}
/*------------------------*/

Bir template fonksiyon birden faazla farklı template argümanına sahip olabilir. Bu durumda pek çok kombinasyon söz konusu olabilir.

/*-----templat3.cpp-----*/
#include <iostream.h>

template <class A, class B>
void fonk(A a, B b)
{
cout << a << endl << b << endl;
}

void main(void)
{
fonk(20L, 100);
fonk(100, 20L);
fonk(1.3, 10L);
fonk('c', 12);
}
/*------------------------*/

Template fonksiyonlar çağırıldığında uygun parametre yapısı bulunamazsa error durumu oluşabilir.

/*-----templat4.cpp-----*/
#include <iostream.h>

template <class T>
void swap(T *a, T *b)
{
T temp;

temp = *a;
*a = *b;
*b = temp;
}

void main(void)
{
int x = 10, y = 20;
swap(&x, &y);
cout << "x = " << x << " " << "y = " << y << endl;
}
/*------------------------*/

Bir template fonksiyon içerisinde başka bir template fonksiyon çağırılmış olabilir. Template argümanı bir sınıf da olabilir. Bir template fonksiyonuyla aynı isimli normal bir fonksiyon bir arada bulunabilir. Bu durumda iki anlamlılık hatası oluşmaz. Normal fonksiyonun template fonksiyona karşı bir üstünlüğü vardır.

Sınıf Çalışması:

template <class T>
void sort(T *p, int size);

Biçiminde sort işlemi yapan bir template fonksiyonu yazınız.

/*-----templat5.cpp-----*/
#include <iostream.h>

template <class T>
void swap(T *a, T *b)
{
T temp;

temp = *a;
*a = *b;
*b = temp;
}

template <class T>
void sort(T *p, int size)
{
int i = 0, j = 0;

for (i = 0; i < size - 1; ++i)
for (j = i + 1; j < size; ++j)
if (p[i] > p[j])
swap(p + i, p + j);
}

void main(void)
{
int a[5] = {3, 8, 4, 7, 6};
int i;

sort(a, 5);
for(i = 0; i < 5; ++i)
cout << a[i] << endl;
}
/*-----------------------*/

Template fonksiyonlar bir şablon belirtir ve kütüphaneye yerleştirilemez. Bu yüzden header dosyalarının içerisine yazılmalıdır.

Template Sınıflar

    Template sınıflarda derleyici nesne tanımlama biçimine uygun bir sınıfın üye fonksiyonlarının hepsini yazar. Genel biçimi:

template <class T>
class X {

};

Bu template argümanı sınıf bildiriminin içerisinde ve bütün üye fonksiyonların içerisinde tür belirten sözcük olarak kullanılabilir. Uygulamada ağırlıklı bir biçimde template sınıflar kullanılmaktadır. Bir tenplate sınıfa ilişkin üye fonksiyon sınıfın dışında aşağıdaki syntax biçimine uygun yazılmak zorundadır.

template <class T>
[geri_dönüş_değeri] sınıf_ismi<T>::fonksiyon_ismi(parametreler)
{

}

Örnek:

template <class T>
void X<T>::fonk(void)
{

}

Bir template sınıfa ilişkin sınıf nesnesi şöyle tanımlanır:

sınıf_ismi <tür ismi> nesne_ismi;

Örnek: Array <int> x;

/*-----templat6.cpp-----*/
#include <stdio.h>
#include <stdlib.h>

template <class X>
class Array {
private:
int size;
X *p;
public:
Array(void);
Array(int n);
X & operator [](int n);
};

template <class X>
Array<X>::Array(void)
{
size = 10;
p = new X[size];
}

template <class X>
Array<X>::Array(int n)
{
size = n;
p = new X[size];
}

template <class X>
X & Array<X>::operator[](int n)
{
if (n >= size) {
printf("Out of range\n");
exit(1);
}
return p[n];
}

void main(void)
{
Array <float> n(5);

for (int k = 0; k < 5; ++k)
n[k] = k;
for (k = 0; k < 10; ++k)
printf("%f\n", n[k]);
}
/*---------------------*/

Stack Sistemine İlişkin Bir template Sınıf Örneği

Stack Sistemi Nedir?

    Stack lifo sistemi ile çalışan bir kuyruk yapısıdır. Stack sisteminin ismine stack pointer denilen bir göstericisi vardır. Bu gösterici o anki stack pozisyonunu tutar. Stack sistemi ile ilgili iki temel işlem vardır:
   
1. Eleman Eklenmesi: Eleman eklenmesi durumunda önce stack gösterişcicsi azaltılır daha sonra stck göstericisinin gösterdiği yere eleman yerleştirilir. stack sistemini başlangıç konumunda sp tahsis edilmiş alanın en aşşasını gösterir. Stack'e eleman eklenmesine push denir. Stack sistemine fazla eleman yerleştirilmesi taşmaya yol açabilir. Bu işleme stack sisteminin üsten taşması denir(stack overflow)

2. Eleman Çekilmesi: Bu durumda stack göstericisinin gösterdiyi yerden eleman çekilir ve stack göstericisi bir artırılır. Stack'ten bilgi alınmasına pop işlemi denir. Eğer fazla sayıda eleman çekilme işlemi uygulanırsa stack aşşağıya doğru taşar. Bu işleme stack underflow denir.

Stack Sisteminin Uygulama Alanları

1. Ters düz etme işlemi. Bir yazıyı ters düz etmek için karakterler tek tek stack sistemine eklenir ve sonra çekilir.
2. Undo işlemleri: Stasck sisteminin her elemanı yapılan işlem hakkında bilgiyi tutan bir yapı şeklindedir. İşlemler yapıldıkça push işlemi ile stack sistemine yerleştirilir. daha sonra undo yapıldıkça pop işlemi ile geri alınır.
3. Aktif pencerenin bulunması işlemi: Üstüste açılan pencerelerde son açılan aktif penceredir o pencere kapatılırsa bir önceki pencere aktif pencere olur.

/*-----stack.h-----*/
/*-----stack.cpp-----*/

nesne tanımlanırken kullanılan template türü başka bir template sınıfı olabilir. X <Y<int>> Z;

Çoklu Türetme (multiple inherritence)

Bir sınıfın birden fazla taban sınıfa sahip olması durumudur. Çoklu türetme durumunda başlangıç fonksiyonlarının çağrılması bildirimde ilk yazılan taban sınıfın başlangıç fonksiyonu önce çağrılacak biçimdedir. Örneğin class C:public A, public B { böyle bir bildirimde önce a, b, c şeklinde başlangıç fonksiyonları çağrılır. Bitiş fonksiyonlarıda c, b, a olacak şekilde tam tersdir.
Türemiş sınıf nesnesi bütün taban sınıf nesnelerinide içerir. Taban sınıf nesnelerinin tüenmiş sınıf içindeki organizasyonu standart olarak belirlenmemiştir. Ancak bildirimde genllikle bildirimde ilk yazılan taban sınıfın vweri elemanları düşük anlamlı adreste oacak biçimde ardışıl bir yerleşim söz konusudur.

/*-----multinhe.cpp-----*/

Çoklu Türetmede Faaliyet Alanı ve İsim Arama

    Çoklu türetme urumunda türemiş sınıf bütün taban sınıflara erişebilir. taban sınıflara erişim konusunda hiç bir önceklik yoktur. Bütün taban sınıflar aynı faaliyet alanı içinde kabul edilir. Yani her iki taban sınıftada aynı isimli bir veri elemanı yada üye fonksiyonu varsa ve erişim çözünürlük operatörü ile yapılmamışsa bu durum iki anlamlılık hatasının oluşmasına yol açar.

int x;wpe5.jpg (1139 bytes)                       wpe7.jpg (999 bytes)int x;
                    wpe8.jpg (1002 bytes)wpe9.jpg (1038 bytes)
                            wpeA.jpg (1077 bytes)
C n;
n.x = 10; /*Bu işlem iki anlamlılık hatasıdır*/

Yani türemiş sınıf üye fonksiyonu içinde bir isim kukllşanıldığında bu isim:

1. Türemiş sınıf faaliyet alanı içinde
2. Taban sınıfların her birinin faaliyet alanı içinde aranır ve bir sıra gözetilmez.

Çoklu Türetmede Türemiş Sınıf Adresinin Taban Sınıf Adresine Atanması Durumu:

    Mademki türemiş sınıfı nesnesinin adesi herhangibir tabna sınıf nesnesinin adresine atana biliyor o halde adresteki işlemler geçerlidir.

           wpeB.jpg (1234 bytes)wpeC.jpg (1217 bytes)
                   wpeE.jpg (1030 bytes)
wpeF.jpg (1049 bytes)

                           wpe10.jpg (1078 bytes)

C x;
A *pa;
B *pb;
pa = &x;
pb = &x;/*işlemleri geçerlidir*/


    Çoklu türetme durumunda türemiş sınıf nesnesinin adresi, herhangi bir taban sınıf göstericisine atandığında derleyici türemiş sınıf nesnesinin taban sınıf veri elemanının adresini göstericiye atar.

Çeşitli Çoklu Türetme Şemaları

1. Bir sınıfın birden fazla doğrudan taban sınıfı olamaz. Başka bir deyimle bir sınıf başka bir sınıfa birden fazla taban sınıflık yapamaz.
                       wpe11.jpg (1206 bytes)         wpe13.jpg (1234 bytes)
                             wpe14.jpg (1018 bytes)wpe15.jpg (1038 bytes)
                                 wpe16.jpg (1245 bytes)

/*Bu işlem olamaz.*/


class B: public A, public A {

};

Böyle bir bildirimde aynı sınıfın veri elemanlarından iki kez oluşturulur. Faaliyet alanı gereği aynı isimli iki taban sınıf veri elemanlarına çatışma çözülerek erişim sağlanamaz.

 

Yorumlar (0)add comment

Yorum Yazın
quote
bold
italicize
underline
strike
url
image
quote
quote
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley
Smiley

busy
 
< Önceki
Advertisement