Yazan : Şadi Evren ŞEKER

Bu yazının amacı, nesne yönelimli programlama kavramlarından birisi olan kapsülleme işlemini (encapsulation), C++ dili üzerinden anlatmaktır.

Kapsülleme veya diğer adıyla veri kapsülleme işlemi, basitçe bir sınıfın (class) dışarıya karşı kapalı hale getirilmesi ve sınıfa erişimin kapsüllenmesi yani engellenmesidir. Bilindiği üzere, sınıflar, özelliklerden (properties) ve metotlardan (methods) oluşmaktadır. Veri kapsüllemesinin amacı, sınıfta bulunan özelliklerin erişimini kontrol altına almak ve sınıfın özelliklerinin dışarıdan erişimini engelleerek, sınıftaki metotlar marifetiyle erişimi kontrol etmektir.

Örneğin bir rasyonel sayı sınıfımız aşağıdaki şekilde olsun.

class rasyonelSayı{

    int pay;

    int payda;

};

Rasyonel sayı işlemlerinin yapılacağı sınıfı yukarıdaki şekilde tanımladık.

public float rasyonelSayı::bölme(rasyonelSayı başkasayı){

    return pay*başkasayı.payda / payda * başkasayı.pay;

}

Yukarıdaki bu metot tanımına göre aşağıdaki şekilde bir main fonksiyonu yazıp kullanmak mümkündür.

int main(){

tamsayı a,b;

a.pay = 4;

a.payda=6;

b.pay = 2;

b.payda=5;

cout << a.bölme(b) << endl;

}

Görüldüğü üzere, a ve b isminde iki adet tam sayı tanımlanmış ve bu sayılar üzerinde bir bölme işlemi uygulanmıştır.

Yukarıdaki sınıf tanımı ve bölme işlemi herhangi bir problem içermezken, aşağıdaki gibi bir bölme işlemi sorun oluşturabilir:

int main(){

tamsayı a,b;

a.pay = 4;

a.payda=6;

b.pay = 0;

b.payda=5;

cout << a.bölme(b) << endl;

}

Yeni kodumuzda, b nesnesinin (object) değeri 0 olarak atanmıştır ve bilindiği üzere matematikte 0’a bölme işlemi bir hatadır. Herhangi bir sayı, 0’a bölünemez.

Bu hatayı kodumuzda engellememiz ne yazık ki mümkün değildir ve bizim tamsayı metodumuzu kullanan herhangi birisi dilediği sayıyı atayabilir.

Bu hatayı engellemek için bölme işleminin içerisinde bir kontrol yazılması yeterlidir.

public float rasyonelSayı::bölme(rasyonelSayı başkasayı){

    if(payda * başkasayı.pay != 0)

        return pay*başkasayı.payda / payda * başkasayı.pay;

    else

        return 0;

}

Yeni fonksiyonumuzda, bölme işleminden önce, yeni payda değeri kontrol edilmiştir. Bu kontrol bölme işleminin güvenli olmasını sağlar ancak hala kodumuzda bir hata bulunmaktadır. Aşağıdaki main fonksiyonunu ele alalım:

int main(){

tamsayı a,b;

a.pay = 4;

a.payda=6;

b.pay = 3;

b.payda=0;

cout << a.bölme(b) << endl;

}

Yukarıdaki yeni kodumuzda, b sayısının payda değeri 0 olarak atanmıştır. Bu durumda bölme işlemi için bir problem olmamakla birlikte b sayısının kendisi için bir problemden bahsedilebilir. Yani b sayısı, bir rasyonel sayı olarak belirsizdir.

O halde sınıfımızdaki pay ve payda değişkenlerinin (properties) doğrudan atanması problem teşkil etmektedir. Bu problemin çözümü ise ancak kontrolünü bizim yaptığımız bir atama yöntemi olan kapsülleme (encapsulation) işlemidir.

class rasyonelSayı{

private:

    int pay;

    int payda;

public:

    void setPay(int x){ pay = x; }

    void setPayda(int x) { payda = x; }

    int getPay(){ return pay; }

    int getPayda(){ return payda; }

};

Yukarıdaki yeni sınıfta, pay ve payda değişkenlerine atama işlemi bizim kontrolümüz altına girmiştir. Kısacası literatürde getter / setter fonksiyonları olarak bilinen ve Türkçeye alıcı/atayıcı fonksiyonları olarak çevirebileceğimiz, ve bir sınıftaki değişkenlerin değerlerini almak veya atamak için kullanılan fonksiyonlar dışında, bu sınıfta bulunan değişkenlere erişimi engellemiş olduk.

Aslında, bir değişken üzerinde yapılabilecek iki temel işlem almak ve atamaktır. Yukarıdaki yeni sınıf tanımımızda henüz problemimizi çözen bir tedbir bulunmasa da artık yazmamız mümkündür:

class rasyonelSayı{

private:

    int pay;

    int payda;

public:

    void setPay(int x){ pay = x; }

    void setPayda(int x) {

        if (x!=0)

payda = x;

}

    int getPay(){ return pay; }

    int getPayda(){ return payda; }

};

Görüldüğü üzere, setPayda fonksiyonu içerisinde kontrol edilerek atama işlemi yapılmaktadır. Dolayısıyla artık payda değeri konulmadan önce 0 olup olmadığı kontrol edilecek ve uygunsa atama işlemi yapılacaktır.

Bu kontrolden sonra main fonksiyonumuz aşağıdaki şekilde olacaktır:

int main(){

tamsayı a,b;

a.setPay ( 4 );

a.setPayda (6);

b.setPay ( 3);

b.setPayda(0);

cout << a.bölme(b) << endl;

}

Görüldüğü üzere, artık sınıfımızdaki değişkenlere, nesnelerin doğrudan erişimi mümkün olmamaktadır. Bu erişim, bizim kontrolümüzde olan fonksiyonlar marifetiyle yapılmakta, dolayısıyla bizim kontrolümüzden geçmektedir.

Yorumlar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir