Polimorfizm

Polimorfizm, aynı fonksiyon elemanının çağrılması durumunda farklı cevaplar alınabildiği için, kalıtımsal ilişkiye sahip faklı nesne sınıfları için bir fırsattır. Bu, sadece temel sınıfın değil aynı zamanda türetik sınıfların davranışlarının da tarif edilebildiği evrensel bir mekanizma oluşturmaya yardımcı olur.

Şimdi yeni bir temel sınıf oluşturalım ve şekil alanını hesaplaması için GetArea() diye bir üye fonksiyon tanımlayalım. Bu fonksiyonu, temel sınıftan kalıtım yoluyla oluşturulmuş tüm varis sınıflarda, belirlenen özel şeklin alan hesabı için gerekli kurallar ışığında, yeniden tanımlayalım.

Karenin (CSquare sınıfı) alanı kenarlara göre hesaplanır;, Daire (class CCircle) alanı ise yarı çapla ifade edilir vb. CShape tipinin nesnelerini içeren bir dizi oluşturabiliriz. Bu, temel sınıfın ve tüm varis sınıfların nesnelerinin saklandığı bir dizi olacaktır. Sonra bu dizinin her elemanı için aynı fonksiyonu çağırabiliriz.

Örnek:

//--- Temel sınıf
class CShape
  {
protected
   int            m_type;                // Şekil tipi
   int            m_xpos;                // merkez noktanın X - koordinatları
   int            m_ypos;                // merkez noktanın Y - koordinatları
public:
   void           CShape(){m_type=0;};   // yapıcı, type=0
   int            GetType(){return(m_type);};// nesne tipine dönüş yapar
virtual
   double         GetArea(){return (0); }// şeklin alanına dönüş yapar
  };

Artık tüm türetik sınıflarda sıfıra dönüş yapan bir getArea() üye fonksiyonu vardır. Bu fonksiyonun uygulaması her bir türetik sınıf için değişecektir.

//--- Daire türetik sınıfı
class CCircle : public CShape            // İki noktadan sonra temel sınıfı tanımlarız
  {                                      // -ki bu, kalıtımın yapıldığı sınıftır
private:
   double         m_radius;              // daire yarı çapı
 
public:
   void           CCircle(){m_type=1;};  // yapıcı, type=1 
   void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return (3.14*m_radius*m_radius);}// daire alanı
  };

Kare sınıfı için yapılacak bildirim de aynıdır:

//--- Kare türetik sınıfı
class CSquare : public CShape            // İki noktadan sonra temel sınıfı tanımlarız
  {                                      // -ki bu, kalıtımın yapıldığı sınıftır
private:
   double          m_square_side;        // kare kenarı
 
public:
   void            CSquare(){m_type=2;}; // yapıcı, type=1
   void            SetSide(double s){m_square_side=s;};
   virtual double  GetArea(){return (m_square_side*m_square_side);}// kare alanı
  };

Kare ve dairenin alanlarını hesaplamak için m_radius (yarı çap) ve m_square_side (kenar uzunluğu) değişkenlerine karşılık gelen değerlere ihtiyacımız oldu için, SetRadius() ve SetSide() fonksiyonlarını bildirime ekledik.

CShape temel tipinden türetilmiş (CCircle ve CSquare) nesnelerinin, programımızda kullanıldığını varsayalım. Polimorfizm, CShape temel sınıfının nesnelerinden bir dizi oluşturulmasını sağlar ama bu dizinin bildirimi sırasında nesneler hala bilinmezdir ve tipleri tanımsızdır.

Dizinin her bir elemanında hangi tip nesnenin yer alacağı kararı programın çalıştırılması sırasında alınır. Bu, uygun sınıfların nesnelerinin dinamik olarak oluşturulmasını ve bundan dolayı, nesneler yerine nesne işaretçilerinin kullanımının gerekliliğini içerir.

new operatörü nesnelerin dinamik şekilde oluşturulmaları için kullanılır. Bu şekildeki her bir nesne delete operatörü ile, tek tek ve açıkça silinmelidir. Bu yüzden CShape tipinin işaretçilerinden oluşan bir dizi bildireceğiz ve aşağıdaki örnekte de görüleceği gibi, her bir (new Sınıf_İsmi) eleman için uygun tipte bir nesne oluşturacağız:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Temel tipin nesne işaretçilerinden oluşan bir dizi bildir
   CShape *shapes[5];   // CShape nesnesinin işaretçilerinden oluşan dizi
 
//--- Burada diziyi türetilen nesnelerle doldur
//--- CCircle tipi nesneler için bir işaretçi bildir
   CCircle *circle=new CCircle();
//--- Daire işaretçisinde nesne özelliklerini ayarla
   circle.SetRadius(2.5);
//--- İşaretçi değerini shapes[0] içine yerleştir
   shapes[0]=circle;
 
//--- Yeni bir CCircle nesnesi oluştur ve işaretçisini shapes[1] içine yaz
   circle=new CCircle();
   shapes[1]=circle;
   circle.SetRadius(5);
 
//--- Burada shapes[2] için değer ayarlamayı bilerek unuttuk
//circle=new CCircle();
//circle.SetRadius(10);
//shapes[2]=circle;
 
//--- Kullanılmayan elemanları NULL (boş) olarak ayarla
   shapes[2]=NULL;
 
//--- Yeni bir CSquare nesnesi oluştur ve işaretçisini shapes[3] içine yaz
   CSquare *square=new CSquare();
   square.SetSide(5);
   shapes[3]=square;
 
//--- Yeni bir CSquare nesnesi oluştur ve işaretçisini shapes[4] içine yaz
   square=new CSquare();
   square.SetSide(10);
   shapes[4]=square;
 
//--- İşaretçilerden oluşan bir dizimiz var bunun büyüklüğünü al
   int total=ArraySize(shapes);
//--- Dizideki tüm işaretçileri bir döngüye geçir
   for(int i=0; i<5;i++)
     {
      //--- Eğer belirli bir indisteki işaretçi geçerliyse
      if(CheckPointer(shapes[i])!=POINTER_INVALID)
        {
         //--- Şeklin tipini günlüğe kaydet
         PrintFormat("%d tipli nesne, %G karesine sahip",
               shapes[i].GetType(),
               shapes[i].GetArea());
        }
      //--- Eğer işaretçi POINTER_INVALID tipinde ise
      else
        {
         //--- Bir hatay ile uyar
         PrintFormat("Nesne shapes[%d] başlatılmadı! Bu nesnenin işaretçişi %s",
                     i,EnumToString(CheckPointer(shapes[i])));
        }
     }
 
//--- Oluşturulmuş tüm dinamik nesneleri silmeliyiz
   for(int i=0;i<total;i++)
     {
      //--- Sadece POINTER_DYNAMIC tipli nesneleri silebiliriz
      if(CheckPointer(shapes[i])==POINTER_DYNAMIC)
        {
         //--- Silindiğinde uyar
         PrintFormat("shapes[%d] siliniyor",i);
         //--- Bir nesneyi işaretçisi aracılığı ile sil
         delete shapes[i];
        }
     }
  }

Bir nesne delete operatörü ile silindiğinde, işaretçi tipinin kontrol edilmesi gerektiğini lütfen not edin. Sadece POINTER_DYNAMIC tipine sahip işaretçiler "delete" kullanılarak silinebilir. Diğer işaretçi tiplerinde ise bir hata dönülecektir.

Ama polimorfizm, fonksiyonların kalıtım sırasında yeniden tanımlanmasının yanında, bir sınıf içindeki farklı parametre kümelerine sahip olan aynı fonksiyonların uygulamasını da içerir. Bu, sınıfın aynı isimde ama farklı tip ve/veya parametre kümesine sahip fonksiyonlara sahip olabileceği anlamına gelir. Bu durumda polimorfizm fonksiyonların aşırı-yüklenmesi yoluyla uygulanır.

Ayrıca Bakınız

Standart Kütüphane