Yazan : Şadi Evren ŞEKER

Bu yazının amacı, C++ dili için, nesneler arasında kurulabilecek olan ilişki tiplerini açıklamaktır.

Temel olarak bir nesne kendi özellikleri ve metotları bulunan bir varlıktır. Nesne yönelimli programlama modelinde, nesnelerin özelliklerini paylaşmak veya diğer nesnelerin metotlarına erişmek için birbirleri ile iletişime girmeleri gerekir.

Bu anlamda inceleyeceğimiz 4 temel ilişkiden bahsedebiliriz. Bu ilişki tipleri nesnelerin özlük yapılarını bozmadan, dışarıdaki bir nesne ile kurdukları ilişki türüdür.

  • Sınıflar (Class) arasında kurulan “bir çeşit” (a-kind-of) ilişkisi
  • Nesneler (object) arasında kurulan “bir” (is-a) ilişkisi
  • Sınıflar (ClasS) arasında kurulan “parçası” (part-of) ilişkisi veya “sahiplik” (has-a) ilişkisi
  • Miras (Inheritance) ilişkisi

Yukarıdaki bu 4 tip ilişki için aşağıdaki örnekleri verebiliriz.

Öncelikle iki adet sınıf tanımını aşağıdaki şekilde yapalım :

Nokta sınıfı aşağıdaki şekilde kodlanmış olsun:

  class Nokta {
  özellikler:
  public : 
    int x, y

  metotlar:
    setX(int yeniX)
    getX()
    setY(int yeniY)
    getY()
  }

Ayrıca çember için aşağıdaki kodu yazalım:

  class Çember {
  özellikler:
    int x, y,
        Çap

  metotlar:
    setX(int yeniX)
    getX()
    setY(int yeniY)
    getY()
    setÇap(yeniÇap)
    getÇap()
  }

Yukarıdaki bu sınıf tanımlarından sonra artık ilişki tiplerimizi belirleyebiliriz.

“Bir Çeşit” ilişkisi

Bu ilişki tipinde, sınıflar arasında birsinin diğer çeşitten olması vurgulanır. Örneğin nokta ile çember arasında “bir çeşit” ilişkisi bulunuyorsa ve biz “çember bir çeşit noktadır” diyebiliyorsak. Bu tanımı iki sınıf üzerinde yapabiliriz.

Bu çıkarım, yukarıdaki örnek için doğrudur. Bunun sebeplerini aşağıdaki şekilde sayabiliriz:

  • İki sınıfta da x ve y özellikleri bulunur. Nokta sınıfı için x ve y değeri, noktanın 2 boyutlu uzaydaki konumunu belirlerken, Çember sınıfı için, çemberin merkezinin konumunu belirler. Dolayısıyla, x ve y iki sınıf için de aynı anlamdadır.
  • İki sınıfta da x ve y özellikleri için getter / setter ( alıcı verici) metotları tanımlanmıştır ve iki sınıf için de bu metotların anlamı aynıdır.
  • Çember sınıfında, ilave olarak bir çap bilgisi bulunur.

Yukarıdaki bu listeye göre, çember sınıfının bir çeşit nokta olduğunu ve noktanın bütün özelliklerini taşıdığını söylemek mümkündür.

“Bir” İlişkisi

Bu ilişki tipi, yukarıda anlatılan “Bir Çeşit” ilişkisinin tamamen aynısıdır. Tek farkı, sınıflar arasında değil de nesneler arasında tanımlı bir ilişki modeli olmasıdır. Yani yukarıdaki tanımlı sınıflardan üretilen nesneler üzerinde kurulabilir. Bu bağlantı türü, literatürde ISA veya is-a şeklinde yazılan ve Türkçeye “bir” şeklinde çevrilen ilişkidir.

Örneğin, çember nesnesi, özellikleri itibariyle bir noktanın çapı olan halidir. Dolayısıyla çember bir noktadır. Şeklinde kurulan cümledeki “bir” kelimesi bu bağlantı tipini ifade eder.

Yukarıdaki yeni şekilde dikkat edileceği üzere çember ve nokta kutuları, köşeleri yuvarlak şekilde çizilmiştir. Bu UML standardı olarak, nesneleri ifade eden gösterim biçimidir. Bir önceki şekilde olduğu gibi köşeli kutlar, sınıf ifade eder.

“parçası” ilişkisi

Bu ilişki türünde, bir nesne, diğer bir nesneyi bir özelliği olarak barındırır. Aslında bir nesnenin alt nesnesi olması durumudur. Parçası ilişkisinde bu ilişki türü, sınıflar arasında tanımlıdır. Örneğin bir araba sınıfının, tekerlek sınıfını bulundurması düşünülebilir. Yani her arabada tekerlek vardır.

  class Araba {
  özellikler:
    Tekerlek tekerlek
    Motor motor
    Nokta konum
  metotlar:
    set(Nokta konum)
  }

Yukarıdaki örnekte, Araba sınıfının, konum, tekerlek ve motor özellikleri bulunmaktadır. Buna göre bu sınıftan üretilen her araba bu özellikleri taşır ve farklı değerlere sahiptir. Örneğin her arabanın farklı motor özellikleri ve farklı tekerlek bilgileri olabilir. Benzer şekilde her arabanın konumu da farklı olabilir. Örneğimizde, bu dış sınıfların her biri, Araba sınıfının bir parçasıdır.

Yukarıdaki şekilde görüldüğü gibi, sınıflar arasında, parçasıdır şeklinde bir ilişki kurulmuştur.

“Sahiplik” ilişkisi

Bu ilişki türü, bir önceki “parçası” ilişkisinin tam tersidir.

Bu ilişki türüne göre, Araba, tekerleğe, konuma ve motora sahiptir.

Kalıtım İlişkisi

Bu ilişki türü, “bir çeşit” ve “bir” ilişki türlerinin birleşimi olarak düşünülebilir.

Literatürde miras ilişkisi şeklinde de kullanılan bu ilişkiye göre bir sınıftaki özelliklerin diğer sınıfa doğrudan geçmesi mümkündür. Örneğin bir noktanın taşıdığı özelliklerin hepsi, çember tarafından taşınmaktadır. Öyleyse bu özelliklerin yeniden çemberde tanımlanmasına gerek duyulmaz. Çember, nokta sınıfından kalıtım yoluyla özellikleri alırken, kendisine özgü, farklı olan özellik ve metotları tanımlar.

Yukarıdaki şekilde görüldüğü üzere, iki nesne arasındaki kalıtım ilişkisi, miras almak şeklinde ifade edilebilir. Miras ilişkisi için genelde ata / torun (ancestor / decestor ) veya ebeveyin / çocuk (parent / offspring) ifadeleri kullanılabilir. İlişkinin, ata olan kısmını gösteren bir üçgen konulması ve nesnelerin alt / üst şeklinde yerleştirilmesi, genelde miras ilişkisini ifade eder. Bu kullanım ayrıca UML standardında da geçmektedir.

Örnek olarak çalışan ve bu çalışandan türetilen bir mühendis sınıfını düşünelim.

Yukarıdaki bu şeklin C++ dilindeki kodlaması aşağıda verilmiştir.


class Çalışan {
public:
  Çalışan(string isim, float odemeOrani);
  string getIsim() const;
  float getOdemeOrani() const;
  float odeme(float calismaSaati) const;
protected:
  string Isim;
  float OdemeOrani;
};

Çalışan::Çalışan(string isim, float odemeOrani)
{
  Isim = isim;
  OdemeOrani = odemeOrani;
}

string Çalışan::getIsim() const
{
  return Isim;
}

float Çalışan::getOdemeOrani() const
{
  return OdemeOrani;
}

float Çalışan::odeme(float calismaSaati) const
{
  return calismaSaati * OdemeOrani;
}

Yukarıdaki kodda, bir çalışan sınıfının özellikleri ve metotları verilmiştir. Bu kodu kullanarak aynı özellikleri taşıyan mühendis sınıfı da aşağıdaki şekilde verilsin.

class Muhendis {
public:
  Muhendis(string isim,
          float odemeOrani,
          bool maasliMi);

  string getIsim() const;
  float getOdemeOrani() const;
  bool getMaasli() const;

  float odeme(float calismaSaati) const;

protected:
  string Isim;
  float OdemeOrani;
  bool maasli;
};
Muhendis::Muhendis(string isim,
                 float odemeOrani,
                 bool maasliMi)
{
  Isim = isim;
  OdemeOrani = odemeOrani;
  maasli = maasliMi;
}

string Muhendis::getIsim() const
{
  return Isim;
}

float Muhendis::getOdemeOrani() const
{
  return OdemeOrani;
}

bool Muhendis::getMaasli() const
{
  return maasli;
}

float Muhendis::odeme(float calismaSaati) const
{
  if (maasli)
    return OdemeOrani;
  /* else */
  return calismaSaati * OdemeOrani;
}

Yukarıdaki bu iki sınıfta, görüldüğü üzere, ortak olan özellikler bulunmaktadır. Bu ortaklıktan faydalanarak kurulacak miras ilişkisi için aşağıdaki şekilde C++ kodu yazılmalıdır.

class Muhendis: public Çalışan {

Yukarıdaki bu yazımda, iki sınıf ismi arasında kullanılan : (iki nokta üst üste) işareti, sağdaki sınıftan, soldaki sınıfım kalıtım yoluyla bilgi aldığını gösterir.

Burada Çalışan sınıfının başında, ayrıca erişim belirleyici (Access modifier) çeşitlerinden “public” kelimesi kullanılmıştır. Burada 3 ihtimal bulunur:

  • public kalıtım
  • protected kalıtım
  • private kalıtım

Kalıtım modelinin public olması, yani yukarıdaki örnek için Çalışan sınıfının başında public yazılması durumunda, Mühendis sınıfı, Çalışan sınıfının bütün özelliklerine erişir. Yani Çalışan sınıfında bulunan özellikler, public veya private olması farketmeksizin, Mühendis sınıfının, private özellikleri olarak miras alınır.

Protected kalıtım modelinde ise, Çalışan sınıfında bulunan private hariç bütün özelliklerini, kendisinin protected özelliği gibi miras alır.

Yorumlar

  1. ahmet_taha

    hocam allah razı olsun paylaşımlarınız nesneye yönelik kaynak sıkıntısı çekiyordum bu siteyi bulana kadar başarılarınızın devamını dilerim

  2. Uğur ÖZGEN

    hocam peki class çalışan’ın yapıcılarını class çalışan sınıfından kalıtımla oluşturdugumuz başka bir sınıf kullanabilirmi?

  3. Şadi Evren ŞEKER Article Author

    Elbette kullanabiliriz. Yapıcı fonksiyonlar ( constructor, veya inşa fonksiyonu) bir miras ilişkisi (inheritace) içerisinde çalıştırılabilir.

    Çağırmak için super( parametreler ) şeklinde kullanabilirsiniz. Buradaki super fonksiyonu, atasının inşa fonksiyonu (constructor) demektir. Bazı dillerde bu fonksiyon, yine inşa fonksiyonu (constructor) içerisinde çağırılmalı ve inşa fonksiyonunun ilk satırı olmalıdır.

    Örneğin java için

    class X{
     public X(int a){
       System.out.println("sayi : " + a);
     }
    }
    class Y extends X{
     public Y(int a){
       super(a);
     }
    }
    public class deneme{
     public static void main(String args[]){
      Y y  = new Y(4);
     }
    }
    

    Yukarıdaki kod çalıştırıldığında ekrana ” sayı : 4 ” yazısını basar. Görüldüğü üzere Y sınıfının inşa fonksiyonu, X sınıfının inşa fonksiyonunu çağırmıştır ve bu çağırma işlemi sırasında miras ilişkisinden (inheritance) istifade edilmiştir.

    başarılar

  4. Şadi Evren ŞEKER Article Author

    get ve set fonksiyonları (Getter setter olarak da geçer) bir sıfının kapsüllenmesi için kullanılır. Basitçe bir sınıfın özelliklerine doğrudan erişim tehlikeli ve istenmeyen bir durumdur. Bunun yerine sınıfın özelliklerine erişmek için (değer atamak için set, değeri almak için set fonksiyonları) kullanılır.

    Detaylı bilgi için aşağıdaki yazıları okuyabilirsiniz:

    http://www.bilgisayarkavramlari.com/2010/10/25/c-dili-ile-kapsulleme-encapsulation/
    http://www.bilgisayarkavramlari.com/2007/12/17/kapsulleme-encapsulation/

Uğur ÖZGEN için bir cevap yazın Cevabı iptal et

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