Showing posts with label sanal metotlar. Show all posts
Showing posts with label sanal metotlar. Show all posts

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.

Wednesday, October 31, 2012

Sanal Metotlar Örneği (c#)


Temel Ev Sınıfı:

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

   /*kalitimda türetilen classların namespaceleri aynı olması tek bir referans üzerinden erişmemiz için kolaylık 
      sağlar.*/
namespace emlakci
{
    public class Ev
    {
        private int odasayisi;
        public int Odasayisi
        {
            get { return odasayisi; }
            set { odasayisi = value; }
        }
        private int katno;

        public int Katno
        {
            get { return katno; }
            set { katno = value; }
        }
        private int alan;

        public int Alan
        {
            get { return alan; }
            set { alan = value; }
        }
        private string semt;

        public string Semt
        {
            get { return semt; }
            set { semt = value; }
        }

        public Ev()
        {
        }
        public Ev(int odasayisi, int katno, string semt, int alan)
        {
            this.odasayisi = odasayisi;
            this.katno = katno;
            this.semt = semt;
            this.alan = alan;
        }

        /* virtual sanal anlamına gelir. virtual tanımlanan metotlar override ile tanımlanan metotlar tarafından 
          ezilebilir.*/
        public virtual string EvGoruntule()
        {
            return string.Format(" Odasayisi: {0} Katno: {1} Alan: {2} Semt: {3}", odasayisi, katno, alan, semt);
        }
    }
}


Türeyen Satılık Ev Sınıfı:

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

/*kalitimda türetilen classların namespaceleri aynı olması tek bir referans üzerinden erişmemiz için kolaylık sağlar.*/
namespace emlakci
{
    public class satilikev : Ev
    {
        private int fiyat;

        public int Fiyat
        {
            get { return fiyat; }
            set { fiyat = value; }
        }
        private int kapora;

        public int Kapora
        {
            get { return kapora; }
            set { kapora = value; }
        }

        public satilikev(int odasayisi, int katno, int alan, string semt, int fiyat, int kapora) : base()
        {
            base.Alan = alan;
            base.Katno = katno;
            base.Semt = semt;
            base.Odasayisi = odasayisi;
            this.fiyat = fiyat;
            this.kapora = kapora;
        }

        /*override ezmek anlamına gelir. Base sınıfındaki virual tanımlanmış metodun yerine önceliği alır. Artık
          virtual metot yerine aktif
         * olan sınıf override sınıfı olur. base sınıfındaki virtual metodu yerine öncelikli olarak override sınıflarla 
           işlem yapılır. eğer 
         * override sınıfı bulunmaz ise virtual sınıf ile işleme devam edilir. */
        /* override tanımladığımız metot türetilen sınıftaki virtual metodu yerine çağrışır. bir anlamda virtual 
           metodunu ezer. */

        public override string EvGoruntule()
        {
            return base.EvGoruntule() + " Fiyat: " + fiyat +  " Kapora: " + kapora;
        }
    }
}

Türetilen Kiralık Ev Sınıfı:


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

/*kalitimda türetilen classların namespaceleri aynı olması tek bir referans üzerinden erişmemiz için kolaylık sağlar.*/
namespace emlakci
{
    public class kiralikev:Ev
    {
        public kiralikev()
        {
        }

        public kiralikev(int odasayisi, int katno, int alan, string semt, double kira) : base(/*aşağıdaki tanımları 
                                                                                                                              burada yapabilirdik.*/)
        {
           /*yukarıdaki boş base constructori dolu olsaydı tekrardan base ile ataması yapmamıza gerek 
             kalmayacaktı. */
           base.Odasayisi = odasayisi;
           base.Katno = katno;
           base.Alan = alan;
           base.Semt = semt;
           this.kira = kira;
         
        }

        public double kira;
        public double depozito;

        /*override ezmek anlamına gelir. Base sınıfındaki virual tanımlanmış metodun yerine önceliği alır. Artık 
         virtual metot yerine aktif
         * olan sınıf override sınıfı olur. base sınıfındaki virtual metodu yerine öncelikli olarak override sınıflarla 
            işlem yapılır. eğer 
         * override sınıfı bulunmaz ise virtual sınıf ile işleme devam edilir. */
        /* override tanımladığımız metot türetilen sınıftaki virtual metodu yerine çağrışır. bir anlamda virtual 
         metodunu ezer. */
        public override string EvGoruntule()
        {
            return base.EvGoruntule() + " Kira " + kira + " Depozito: " + depozito;
        }
    }
}




Main Sınıfı:

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

//Not: base sınıf üzerinden kalıtım sınıflarına erişebilme:

namespace kalitimsinifi
{
    class Program
    {
        static void Main(string[] args)
        {
            /*kalitim tüm sınıfları base sınıf üzerinden kullanabilme imkanı verir.
            fakat o sınıflara has alanı görmek için gerçek tipine cast etmemiz gereklidir. */

            Ev ev1 = new kiralikev(1, 1, 1, "1", 1);
            Ev ev2 = new satilikev(2, 2, 2, "2", 2, 2);
            Ev ev3 = new kiralikev(3, 3, 3, "3", 3);
            Ev ev4 = new satilikev(4, 4, 4, "4", 4, 4);
            kiralikev ev5 = new kiralikev(5, 5, 5, "5", 5);
            satilikev ev6 = new satilikev(6, 6, 6, "6", 6, 6);

            Ev[] evler = new Ev[6];
            evler[0] = ev1;
            evler[1] = ev2;
            evler[2] = ev3;
            evler[3] = ev4;
            evler[4] = ev5;
            evler[5] = ev6;
         
            for (int i = 0; i < evler.Length; i++)
            {
                Console.WriteLine(evler[i].EvGoruntule());

                if (evler[i] is kiralikev)
                {
                   /* kiralikev sinifindan bir nesne tanımlıyoruz ve bu nesneye evler[i] nesnesini (kiralikev) 
                    operatörüyle casting edip atıyoruz.)*/

                   kiralikev ke = (kiralikev)evler[i];

                   /* NOT: (evler[i] as kiralikev).depozito deyimi casting ile aynı görevi görür. */
                   Console.WriteLine(" depozito: "+ ke.depozito);
                }
            }

            Console.ReadLine();
        }

    }
}

Sanal Metotlar (c#)


Şu ana kadar bir nesne üzerinden çağırdığımız metotların tamamı derleme zamanında belirgindi. Yani derleme
aşamasında hangi nesne üzerinden hangi metotların çaığrabileceği belliydi. Sanal metotlar yardımıyla çalışma
zamanında metot seçme işinin nasıl olduğunu inceleyeceğiz.

Sanal metotlar temel sınıflar içinde bildirilmiş ve türeyen sınıflar içinde de tekrar bildirilen metotlardır.
Sanal metotlar nesne yönelimli programlama tekniğindeki çok biçimliliği(polimorphism) uygulayan yapılardır.
Temel sınıfta bir sanal metot bildirildiğinde bu temel sınıflar, temel sınıftaki sanal metodu devre dışı bırakarak
kendi metot gövdelerini oluşturabilirler.

Sanal metotlar sayesinde Temel sınıf türünden bir referansa türeyen sınıf referansları aktarıldığında, temel
sınıf referansı üzerinden kendisine aktarılan türeyen sınıfın sanal metodu çağrılabilir. Eğer türeyen sınıf
sanal metodu devre dışı bırakmamış ise temel sınıftaki sanal metot çağrılır. Çağrılan metodun hangi türe ait
olduğu çalışma zamanında belirlenir. Metotların bu şekilde çalışma zamanında belirlenmesine geç bağlama
(late binding) denilmektedir.

Sanal metotlar virtual anahtar sözcüğü kullanılarak bildirilir. Bu anahtar sözcük, metot bildirimin başına
eklenirse soyut metotlar bildirilmiş olur. Türeyen sınıfta, temel sınıftaki soyut netotları devre dışı
bırakmak için ise override anahtar sözcüğü kullanılır.


Sanal metotların etkin kullanılığı bir örnek;

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

namespace SanalMetotlar
{
    class Memeli
    {
        public double Boy;
        public double Agirlik;

        public Memeli(double boy, double agirlik)
        {
            this.Boy = boy;
            this.Agirlik = agirlik;
        }

        virtual public void Konus()  /* Türetilen sınıflar ile işlem yapılacağı zaman, Konus() metodu 
                                    türetilen sınıfta override anahtar sözcüğü ile tanımlanmış ise
                                                   Türetilen sınıftaki metot çağıralacak. */
        {
            Console.WriteLine("ben konusamam");
        }
    }

    class kedi : Memeli
    {
        public string Turu;
        public kedi(string turu, int boy, int agirlik)
            : base(boy, agirlik)
        {
            this.Turu = turu;
        }

        override public void Konus()  /* Kedi sınıfı ile işlem yapılacağı zaman Base sınıftaki virtual ile
                                tanımlanan Konus() metodu yerine buradaki konus() metodu çağıralacak.*/
                               
        {
            Console.WriteLine("Ben bir kediyim");
        }
    }

    class koyun : Memeli
    {
        public string Turu;
        public koyun(string turu, int boy, int agirlik)   : base(boy, agirlik)  /* alınan değerleri türetilen sınıftaki  
                                                          değişkenlere gönderiyor. Base.Boy  tanımlamamıza gerek kalmıyor */
        {
            this.Turu = turu;
        }

        override public void Konus() /* Koyun sınıfı ile işlem yapılacağı zaman Base sınıftaki virtual ile
                                tanımlanan Konus() metodu yerine buraki konus() metodu çağıralacak.*/
        {
            Console.WriteLine("Ben bir koyunum");
        }
    }

    class MainMetodu
    {
        static void Main()
        {
            Memeli memeli1 = new Memeli(20, 30);
            kedi kedi1 = new kedi("Van", 10, 15);
            koyun koyun1 = new koyun("keçiören", 60, 80);

            memeli1.Konus();


            memeli1 = kedi1;
            memeli1.Konus();


            memeli1 = koyun1;
            memeli1.Konus();

           

            Console.ReadLine();

        }
    }
}

ekran çıktısı;

ben konusamam
ben kediyim
ben koyunum  

 Şeklinde olacaktır. Kedi ve Koyun nesneleri ait referans aktarılmasına rağmen çalışma zamanında bu Memeli
 referansı üzerinden Konus() metodunu çağırdığımızda Memeli sınıfındaki Konus() metodu yerine kendisine
 atanan sınıflara ait Konus() metotları çağrılmıştır.

 Sanal metotlar sayesinde temel sınıf referanslarına türeyen sınıf referansları atandığında, temel sınıf
 referansı üzerinden türeyen sınıfa ait metotları çağırabilmekteyiz. Bu yöntemle sadece temel sınıfta sanal
 olarak bildirilmiş metotların türeyen sınıfta devre dışı bırakılmış olan metotlara erişilebilir.