9 Mart 2011 Çarşamba

C# Virtual Nedir?

Virtual, metotlara uygulanan bir anahtar sözcüktür. (Aslında sınıflara da uygulanabilir, tüm abstarct üyeler aynı zamanda virtual’dır. Bunun detaylarına Abstract Nedir adlı yazımda değineceğim.) Bir metotun virtual olması, kalıtıldığı sınıflarda gövdesinin(süslü parantezlerin içi) değiştirilebileceği anlamına gelir. Şimdi bir örnek üzerinde virtual’ı anlamaya çalışalım.

İlk olarak Nokta adında bir sınıf tasarlayalım.

class Nokta

    {

        int _x;

        int _y;

 

        public int X

        {

            get { return _x; }

            set { _x = value; }

        }

        public int Y

        {

            get { return _y; }

            set { _y = value; }

        }

    }

Nokta sınıfı, oluşturacağımız Daire ve Silindir sınıfları için taban sınıf olacak. Şimdi de Nokta sınıfından kalıtım yaparak Daire adlı yeni bir sınıf oluşturalım. Daha sonra oluşturduğumuz bu sınıfa AlanHesapla adında bir metot ekleyelim.

class Daire : Nokta

    {

        int _yariCap;

 

        public int YariCap

        {

            get { return _yariCap; }

            set { _yariCap = value; }

        }

 

        public virtual double AlanHesapla()

        {

            return Math.PI * YariCap * YariCap;

        }

    }

Metotu virtual yaparak, taban sınıfta gövdesinin değiştirilebileceğini vurgulamış olduk. Şimdi Daire sınıfından kalıtım yaparak Silindir adlı yeni bir sınıf tasarlayalım. Bu sınıfta da yine AlanHesapla adında bir metot olsun. Ancak bu metot silindir için farklı bir iş yapacağından, metodun gövdesini değiştirmemiz gerekmektedir. Virtual tanımlanan bir metodun, kalıtılan sınıflarda gövdesinin değiştirilmesine override etmek adını veririz.

class Silindir : Daire

    {

        int _yukseklik;

 

        public int Yukseklik

        {

            get { return _yukseklik; }

            set { _yukseklik = value; }

        }

 

        public override double AlanHesapla()

        {

            return (2 * Math.PI * YariCap * Yukseklik) + 2 * base.AlanHesapla();

        }

    }

Şimdi bu sınıflara ait nesneler oluşturarak aldığımız sonuçları görelim;

class Program

    {

        static void Main(string[] args)

        {

            Daire d = new Daire();

            d.YariCap = 5;

            Console.WriteLine(d.AlanHesapla());

 

            Silindir s = new Silindir();

            s.YariCap = 5;

            s.Yukseklik = 20;

            Console.WriteLine(s.AlanHesapla());

        }

    }

Daire tipinden olan “d” değişkeni üzerinden metot çağrısı yapıldığında Daire sınıfındaki metot, Silindir tipinden olan “s” değişkeni üzerinden metot çağrısı yapıldığında Silindir sınıfındaki metot çalışacaktır. Alacağımız sonuç şu şekilde olmalıdır.

Untitled

 

Yukarıda yaptığımız tasarıma göre, “Silindir has a Daire” dememiz yanlış olmaz. Zaten kalıtımın temel felsefesi “is a” ve “has a” ilişkisi kurmaktır. Acaba bir silindir nesnesini Daire tipinden bir işaretçiye atasak nasıl bir sonuç alırız? Program tarafında tanımlamış olduğumuz silindir nesnesini Daire tipinden d2 adında yeni bir işaretçiye atayalım.

Daire d2 = s;

      Console.WriteLine(d2.AlanHesapla());

Alacağımız sonuç şu şekilde olur.

Untitled2

 

Görünen o ki Silindir sınıfındaki AlanHesapla metodu çalışmış. Smile  Olmasını beklediğimiz sonuç da buydu zaten. Virtual ile yapılan olay, taban sınıfta metodu tanımlamak ve kalıtılan sınıflarda davranışını değiştirmektir. Silindir sınıfında, Daire sınıfında tanımlanmış olan alanHesapla metodunu override ediyoruz, yani davranışını değiştiriyoruz. d2=s dediğimizde ise compiler önce Daire sınıfındaki metoda gider. Metodun virtual olduğunu görünce de eşitliğin sağ tarafındaki nesneye bakar ve metodun burada override edilip edilmediğini kontrol eder. Bizim örneğimizde, Daire sınıfındaki metot, silindir sınıfında override edildiği için, d2.AlanHesapla() dediğimizde  Silindir sınıfdaki AlanHesapla metodunun çalıştığını gördük.

NOT: virtual anahtar sözcüğü private metotlara uygulanamaz. Çünkü amaç, kalıtılan sınıflarda metodun gövdesini değiştirmektir.



16 yorum:

Burak Karatatar dedi ki...

return (2 * Math.PI * YariCap * Yukseklik) + 2 * base.AlanHesapla();
Bu satırın açıklaması nedir acaba ?

Onur Salkaya dedi ki...

Merhaba,

Silindirin alan hesabı formülü = 2.Π.r.h + 2.Π.r.r şeklindedir.

r=yarı çap
h=yükseklik

İlk kısım yanal alanı veriyor, artı işaretinden sonraki kısım da silindirin altındaki ve üstündeki dairelerin alanları. Toplam 2 daire olduğundan, pi r kare formülünü 2 ile çarpıp yanal alana ekliyoruz. Normalde manuel olarak (2.pi.r.r) yazabilirdik ancak Silindir sınıfının taban sınıfı Daire olduğundan ve Daire sınıfında dairenin alanını hesaplayan "AlanHesapla" adlı bir metot olduğundan, direk olarak bunu kullandık. base anahtar sözcüğü ile içerisinde bulunduğunuz sınıfın taban sınıfına erişebilir ve taban sınıftaki non-static üyeleri kullanabiliriz.

Taha Karaca dedi ki...
Bu yorum yazar tarafından silindi.
Adsız dedi ki...

Daire d2 = s;
Console.WriteLine(d2.AlanHesapla());

Silindir classindan oluşturulan nesnelerin 2 tane alanı var bunlar yükseklik ve yarıçap. Daire clasındanda bir nesne oluşturduğumuz zaman sadece 1 tane alanı var buda yarıçap.

örnekte s nesnesinin yarıçapına 5, yüksekliğine 20 değerlerini girmişiz.

Daire d2 = s;

dediğimiz zaman nasıl oluyoda 2 tane alan içeren S nesnesinin işaretçisi , tek alan içeren d2 nesnesi olabiliyo ? burda karıştı işte biraz. daha açıklayıcı anlatırsanız çok sevinirm çnkü genel yapıyı çok iyi anladm ama bu dediğim kısmı daha iyi anlatabilirsenz sevinirim . Teşekkürler

Adsız dedi ki...

ayrıca Daire d2 = s; dedğimiz zaman d2 nesnesinde değişiklik yapmak istersek eğer sadece yarıçapı değiştrebilirz yükseklik alanına ulaşamiyorz daire işaretçisi oluduğu için. bz d2 nesnesine hangi sınıfın nesnesi diyebilirz peki dairenin mi yoksa silindirin mi ?

Onur Salkaya dedi ki...

Merhaba,

Burada yapılan olay inheritance'dır. Inheritance (kalıtım) ile nesneler arasında belli ilişkiler kurabiliriz. Silindir sınıfının tanımına dikkat ederseniz " class Silindir : Daire " gibi bir ifade göreceksiniz. Bunun anlamı şudur " Silindir has a Daire". Dolayısı ile ben bir silindir nesnesini taban sınıfı olan Daire tipinden bir işaretçiye atayabildim.

Aynı örneğe şu açıdan bakın;

int a = 45 ;
object nesne = a ;

Yukarıdaki kod bloğunda şunu yaptık; Kalıtım felsefesine göre " int is an object" olduğu için. int tipinden bir nesneyi object tipinden bir işaretçiye atayabildik.

Faydalı olması dileği ile..

Adsız dedi ki...

Benim burda tam olarak anlatmak istediğim şu , silindir has daire tamam bunu çok iyi anladım. Diyelimki daire d1 = new silindir(); bu şekilde d1 nesnesini oluşturduğumuzda " d1. " dediğimizde silindire ait yükseklik propertysini görebilecekmiyiz cevap hayır. (cast ederek ulaşabilir tabiki).
Şimdi, Silindir s = new Silindird(); s.YariCap = 5; s.Yukseklik = 20; dedik sonrada Daire d = s; dediğimizde d. yaptığımızda yükseklik propertysne ulaşamıyoduk , ama s.Yukseklik = 20 dedik, bu atama işlemi nasıl oldu bunu anlamadım..

Onur Salkaya dedi ki...

Merhaba,

Benim de anlatmak istediğim şey şuydu; burada bir atama işlemi var sadece, yani bir nesne örneğini bir işaratçiye atadık.

Silindir s = new Silindir(); şeklinde bir kod çalıştığında önce ram'in heap bölgesine Silindir tipinden bir nesne örneği çıkar. Ardından da stack bölgesine "s" adlı bir işaretçi çıkar. "s" adlı işaretçide "new Silindir()" diyerek oluşturduğumuz (yarı çapı ve yüksekliği olan) nesne örneğinin adresi bulunur.

Ardından Daire d = s ; şeklinde bir atama yaptığımızda. Ram'in stack bölgesinde "d" adlı bir işaretçi oluşur. Ardından bu işaretçiye "s" işaretçisinin içerisindeki nesne adresi verilir. Bu atamanın yapılabilmesi için de bu iki tip arasında (silindir ve daire) bir kalıtım hiyeraşisi olması gerekir.

"d" adlı işaretçi silindir nesnesini ve bu özellikleri üzerinde taşımıyor. Sadece ram'in stack bölgesinde bulunan Silindir tipindeki nesne örneğinin adresini taşıyor.

Adsız dedi ki...

" Bu atamanın yapılabilmesi için de bu iki tip arasında (silindir ve daire) bir kalıtım hiyeraşisi olması gerekir. " Şimdi çok iyi oturdu çok teşekkür ederim gerçekten..

Adsız dedi ki...

BEN 40 YASINDAN SONRA BILGISAYAR OGRENMEYE CALISAN VE YASI 45'E GELDIGINDE C# DIYE BIR PROGRAMLAMA DILI OLDUGUNU OGRENEN BIR KISI OLARAK, SUNU BELIRTMELIYIMKI, GERCEKTEN ACIKLAMALARINIZ COK GUZEL, INANIYORUM KI EGER BEN BILE ACIKCA VE SOMUT OLARAK ANLAYABILIYOR ISEM, HERKES RAHATLIKLA ANLAYABILIR. YUKARIDA OGRETTIKLERINIZDEN DOLAYI SIZE MINETTARIM.
SAYGILARIMLA
ISMAIL

Onur Salkaya dedi ki...

Merhaba,

Güzel yorumlarınız için çok teşekkür ederim, bunları duymak beni mutlu etti.

Faydalı olmasına sevindim.
Başarılar dilerim.

Adsız dedi ki...

Her bir sorunun cevabı var ve siz bu cevapları mükemmel bir şekilde anlatıyorsunuz çünkü ezberci değil mantığı çok iyi biliyorsunuz , emeğiniz elinize sağlık kafama takılan her bir soruda cevapları burada buluyorum , başarılarınızın devamını dilerim en yakında zamanda bir eğitim seti çıkarırsınız bilgilerinizden bizi mahrum etmeyin mükemmel bir anlatımınız var.

Serdar dedi ki...

bu anlattığınız polimorfizim olmuyormu ? çünkü çok benziyor farkı varmı ?

Onur Salkaya dedi ki...

Merhaba,

Evet , polymorphism dediğimiz felsefenin kullanım şekillerinden biridir. Aynı şekilde, abstract ya da interface kullanımlarını da bu bağlamda değerlendirebiliriz.

Unknown dedi ki...

Virtual property neden kullanılır acaba yardımcı olabilir misiniz.

Onur Salkaya dedi ki...

@tuba altay

Property'ler aslında metottur. Bizler bir property yazdığımızda, bu property derleyici tarafından get ve set metotlarına dönüştürülür. Dolaysyıyla siz bir metodun (bir property de metot demiştik) davranışını değiştirmek isterseniz, onu virtual olarak işaretlersiniz. Özetle amaç; kalıtılan üst sınıflarda get ve set bloklarının işlevlerini değiştirmektir

Yorum Gönder