Friday, November 2, 2012

Çok Biçimlilik(Polymorphism) (c#)


Tek bir metot ile birçok sınıfa ait farklı versiyondaki metotlar çağrılabilmektedir. Üstelik bu işlem aynı
nesne üzerinden olmaktadır. Bir nesnenin bu şekilde çoklu özellik göstermesine çok çeşitlilik(polymorphism)
denilmektedir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Polymorphism
{
    class Sekil
    {
        public double Boy;
        public double En;

        public Sekil(double boy, double en)  /* kurulurken boy ve en değerlerini alan constructor yazdık */
        {
            this.Boy = boy; /* base sınıfta sadece boş constructor olduğunda kullanılması yaygındır.*/
            this.En = en;
        }
        public Sekil()
        {
        }
        virtual public double Alan() /*sanal alan metodu yazdık. türeyen sınıfta Alan() metodu varsa buradaki 
                                                  ezilecektir.*/
        {
            return 0;
        }
    }

    class Dortgen : Sekil /* sekil sınıfından dortgen sınıfını türettik*/
    {
        public Dortgen(int boy, int en)
            : base(/*boy,en*/)       /* alınan değerleri türetilen sınıftaki   değişkenlere gönderiyor.
                                                 Base.Boy tanımlamamıza gerek olmuyor. */
     /*eger base sınıfta (boy,en) constructorı yoksa bunu kullanamayız.*/
         
        {
            base.Boy = boy; /* base sınıfta sadece boş constructor olduğunda kullanılması yaygındır.*/
            base.En = en;
        }

        public override double Alan()  /* eger kurulan sınıf dortgen olursa sekil sınıfındaki Alan() metodu yerine 
                                                       buradaki Alan() çağırılacak*/
        {
            return En * Boy;
        }

    }
    class Ucgen : Sekil
    {
        public Ucgen(int boy, int en)
            : base(boy, en) /* eger base sınıfta (boy,en) constructorı yoksa bunu kullanamayız.*/
        {
        }

        public override double Alan()  /* eger kurulan sınıf dortgen olursa sekil sınıfındaki Alan() metodu yerine 
                                                      buradaki Alan() çağırılacak*/
        {
            return En * Boy / 2;
        }
    }

    class MainMetodu
    {
        public static void AlanBul(Sekil sekil)
        {
            Console.WriteLine("seklin alanı: " + sekil.Alan());
        }
        static void Main()
        {
            Ucgen ucgen = new Ucgen(10, 50);
            AlanBul(ucgen);

            Dortgen dortgen = new Dortgen(10, 50);
            AlanBul(dortgen);

            Sekil sekil = new Sekil(10, 50);
            AlanBul(sekil);

            Console.ReadLine();
        }
       
    }
}


ekran çıktısı:

250
500
0
   şeklinde olacaktır.
 
   Gördüğümüz gibi statik AlanBul() metodu Sekil türünden bir nesne beklemesine rağmen Sekil Türünden
   türeyen Ucgen ve Dortgen nesnelerini de kabul etmektedir. Üstelik bu Ucgen Ve Dortgen nesneleri metodun
   parametresi olan Sekil nesinesine aktarilmasına rağmen Ucgen ve Dortgen sınıflarındaki Alan() metotları
   çağrılabilmiştir. Bunu sağlayan da süphesiz Alan() metodunun sanal olarak bildirilmesi ve Türeyen
   sınıflarda bu metodunun devre dışı bırakılmasıdır.
 
   Türeyen sınıflar, temel sınıflardaki sanal metotları devre dışı bırakmak zorunda değildir. eğer türeyen
   sınıfta ana sınıftaki sanal metodu ezecek bir sınıf tanımlanmadıysa türeyen sınıf için de ana sınıftaki
   sanal metot geçerli olur. Aşağıda örneklendirmek gerekirse;
 
   class Dortgen : Sekil
   {
     puplic Dortgen(int boy, int en):base (boy,en)
{
}
}
 Dortgen metodumuz bu şekilde olsaydı
 Dortgen dortgen= new Dortgen(10,50);

 dortgen.Alan()  için ana sınıftaki yani Sekil sınıfındaki virtual tanımlanan Alan() metodu geçerli
 olacaktı.

 Hiyerarşik sınıf yapılarında bu kural geçerlidir. Hiyerarşik yapılardaki sınıflarda yukarıdaki gibi
 bir kullanım söz konusu olursa en alttan en üste doğru Alan() metodunun ilk devre dışı bırakıldığı
 sınıfa ait metot çağırılır.


 Çok çeşitlilik ve metotların devre dışı bırakılması ile ilgili öğrendiklerimizi pekiştirmek gerekirse;


 1. Eğer metot sanal olarak bildirilmemişse, derleyici nesnelerin tür bilgisinden faydalanarak derleme
 zamanında hangi metodun çağrılcağını bilir.

 2. Eğer metot sanal olarak bildirilmiş ise, derleyici derleme aşamasında ürettiği kod ile çalışma
 zamanında referansın türüne göre ilgili sınıfın devre dışı bırakılmış metodunu çağırır.

 3. Hangi metodun çağıracağının çalışma zamanında belirlenmesine geç bağlama(late binding)
          denilmektedir.

 4. Sanal metot bildirmek için virtual anahtar sözcüğü kullanılır.

 5. Türeyen sınıfta, temel sınıftaki sanal metodu devre dışı bırakmak için override anahtar sözcüğü
 kullanılır.

 6. Türeyen sınıfta devre dışı bırakılan metotların temel sınıftaki sanal metotların ismi aynı olamk
 zorundadır.

 7. Türeyen sınıfta devre dışı bırakılan metotların parametrik yapısı temel sınıftaki parametrik yapısı
 ile aynı olmak zorundadır.

 8. Statik metotlar sanal olarak bildirilemez.

 9. Türeyen sınıflar, temel sınıftaki sanal metotları devre dışı bırakmak zorunda değildir. Bu durumda
 temel sınıf referansı üzerinden temel sınıfa ait metot çağırılır.