Bu yazım da C#’ta inheritance(Kalıtım,Miras) kavramından bahsedeceğim.Inheritance,OOP(Object Oriented Programming – Nesne Yönelimli Programlama) tekniklerinden birisidir.Sınıflar arası hiyerarşik yapı kurabilmek, oluşturmak için kullanılır.Bir sınıf,başka bir sınıftan türeyerek(kalıtım alma) , o sınıfın public ve protected tanımlı yapılarını devralır.Kalıtım alan sınıfa : Derived Class , kalıtım veren sınıfa : Base class denir.Türeyen sınıf,türeten sınıf olarak isimlendirilir.
ACCESS MODIFIERS (ERİŞİM BELİRLEYİCİLERİ)
Protected
Eğer bir class içerisinde bir eleman,bir metod protected olarak tanımlanmışsa, o yapı o class için private ve o classtan türeyen classlar için public davranış sergiler.Yani protected elemanlar sadece o class ve o classtan türeyen classlar da kullanılabilirler.O classtan türemeyenler de kullanılmazlar.
Internal
Eğer bir class içindeki ifade internal ile işaretlenmişse sadece o assembly(o solution, o exe) içinde kullanılabilirler(Kalıtım alsın ya da almasın).Diğer yerlerde kullanılmaz.Mesela bir .dll projesi içindeki bir classta internal işaretli yapılar, o .dll in eklenip kullanıldığı başka solutionlar içindeki yapılarda kullanılamazlar.
Protected Internal
Başka bir assembly içinde, eğer bir class, bu assemblydeki bir classtan türemişse,o class içindeki protected internal ifadeler protected olmalarından dolayı kullanılabilirler, ama türemeyen classlar içinde bu elemanlar aynı zamanda internal oldukları için kullanılamazlar.
Public ve Private
Bu erişim belirliyicilerini zaten biliyoruz.Birdaha değinmek gerekirse;
Public erişim belirleyicisi ile oluşturulan metod ya da property ler oluşturulduğu class dısından da erişilebilir.
Private erişim belirleyici ile oluşturulan metod ya da property ler oluşturulduğu class dışında başka bir class ta kullanılamazlar.
C# da oluşturulan her class aslında Object classından türemiştir.Yani her class object classından otomatik türetilir.Bir sınıf yazıp,oluşturduğumuz sınıftan nesne yaratırsak eğer,o nesnenin içinde otomatikman Equals(),GetHashCode(),GetType() ve ToString() metodlarını görürüz.Halbuki biz bu metodları sınıfımıza yazmamıştık.Bu metodlar Object sınıfından kalıtım yoluyla gelirler.Her nesneden ulaşılabilen bu metodlar aslında object sınıfının metodlarıdır.
Bir sınıf sadece tek bir sınıftan kalıtım alabilir.Aynı anda birden fazla sınıftan kalıtım alamaz.Fakat ileride göreceğimiz interface yapıları kullanılarak bu sıkıntı aşılacaktır.
Türeten sınıf(base class) , türeyen sınıf(derived class) için base olarak kabul edilir.Yani her sınıfın base si,kendi türediği sınıftır.Hiyerarşinin en tepesindeki sınıf her sınıfın base i değildir.Yani;
A->B B->C(A dan B türesin,B den de C türesin).Burada C nin basesi B sınıfıdır.A sınıfı C nin basesi değildir.Her sınıfın basesi türediği sınıfıdır.
Şimdi bu sayfada kalıtımla ilgili teorik olarak bilgiler verdim.İkinci sayfada mantığıyla ilgili konuşalım.
Kalıtım mantığını ben Aristotales felsefesine benzetiyorum 🙂
Şimdi İnsan,Kızlar ve Erkekleri düşünelim.Burda hangisi Base Class,hangisi Derived Class olacaktır.
Şimdi düşünelim,
Erkekler ve Kızlar gruplarının ikiside sonuçta insan olduğu için, ikisinin de ortak özellikleri mevcuttur.Yani bir Erkeğin de Kızın da adı,soyadı,yaşı vs. gibi özellikler ortaktır.Ancak Erkeklerin ve Kızların kendine has,bir diğer grupta bulunmayan özellikleri vardır.Bunlar Erkekler de sakal,bıyık vs. olurken, Kızlar da makyaj yapmak,adamı hasta etmek gibi kendilerine has özellikleri vardır.Durum böyleyken ikisinde de ortak olan özellikler insan sınıfında bulunması gerekirken,kendilerine has özellikler kendi sınıflarında bulunmalıdır.Yani burda Base Class İnsan sınıfı olurken,Derived Class Erkek ve Kızlar olacaktır.Erkekler ve Kızlar ad,soyad vs. gibi insan için ortak olan özellikleri insan sınıfından kalıtımla alacaklardır.(Kendi sınıflarına da bu özellikleri tanımlayabiliriz ama kalıtımın amacı bu hiyerarşiyi kurmaktır.)Ve kendine has özelliklerini kendi sınıflarından alacaklardır.Bu mantıkta hiyerarşiyi uzatabiliriz.
Umarım kalıtımın mantığını anlatabilmişimdir.
Bir sonraki sayfa da C#’ta pratik olarak kalıtım konusuna gireceğiz.Artık zamanı geldi…
Şimdi bir şirketin hiyerarşisini oluşturalım.
Şirketin personellerini,satış danışmanlarını ve şirketin iş yaptığı müşterileri kalıtım yoluyla hiyerarşik bir şekilde yazalım.
Şimdi düşünelim,personellerin,müşterilerin ve satış danışmanlarının ortak özellikleri nelerdir.Hepsi bir insan olduğu için adı,soyadı,yasi vs.. gibi özellikleri ortak.O halde bunları kalıtımla alacakları bir sınıf oluşturalım.Ben bu sınıfa İnsan.cs ismini veriyorum.Şimdi bu sınıfı oluşturalım.
---İnsan.cs---
class Insan
{
public string Adi { get; set; }
public string SoyAdi { get; set; }
public string Yasi { get; set; }
public string Cinsiyet { get; set; }
}
Yukarıda aklıma geldiği kadar ortak özellikleri yazdım.Şimdi personelin sınıfını oluşturalım.Personeller.cs isimli class dosyasın da hazırlıyorum.
---Personeller.cs---
class Personeller:Insan
{
public string PersonelMaasi { get; set; }
public string PersonelUnvani { get; set; }
public string PersonelCalismaSuresi { get; set; }
}
Şimdi Personeller.cs sınıfın da yazdıklarımız personellere has özelliklerdir.Yani her insanın maaşı,ünvanı ve calisma süresi olmaz.Bu yüzden dolayı bu özellikler Personeller.cs sınıfın da yazılmıştır.Insan.cs sınıfından diğer özellikleri kalıtım yoluyla alacağız.Bunuda sınıf isminin yanında “:” operatörü ile Base classımızın ismini yazarak gerçekleştiriyoruz.”class Personeller:Insan”, bu ifade sayesinde Insan.cs sınıfındaki özellikleri Personeller.cs sınıfına kalıtımla almış olduk.
Şimdi ise satış danışmanlarının sınıfını hazırlayalım.SatisDanismani.cs sınıfında hazırlıyorum.
---SatisDanismani.cs---
class SatisDanismani:Personeller
{
public string SatisSayisi { get; set; }
}
Şimdi dikkat ederseniz,SatisDanismani.cs sınıfının Base Classı Personeller.cs sınıfıdır.Bunun sebebi,satış danışmanları şirketimizin zaten bir personelidir.Ve personellerin has özellikleri satış danışmanında da olması gerekiyor.Bunuda Personeller.cs den kalıtımla alıyor.Şimdi soracaksınız.Peki satış danışmanının adı,soyadı vs.. gibi bilgileri yok mu? diye.Evet var.Personeller.cs sınıfı kalıtım yoluyla Insan.cs sınıfından o özellikleri aldığı için,otomatikman SatisDanismani.cs sınıfına da yansıyacaklardır.Hiyerarşiyi bu şekilde rahatça düzenleyebiliyoruz.Tabi her personellin yaptığı iş satış danışmanlığı olmadığı için, her personelin satış sayısı olmayacaktır.O yüzden kendine has özelliğini SatisDanismani.cs sınıfında yazdım.Diğer geri kalan özellikleri kalıtım yoluyla almış olacak zaten.
Şimdi de müşteriler sınıfını oluşturalım.Müşteriler bizim şirketimizin personeli olmadığına dikkatinizi çekerim.Bu sınıfı Musteriler.cs sınıfında oluşturuyorum.
---Musteriler.cs---
class Musteriler:Insan
{
public string MusteriSirketi { get; set; }
}
Müşteri de bir insan olduğundan olağan özellikleri Insan.cs sınıfından alıyor.Kendine has özelliği olan şirketini kendi sınıfına yazıyoruz.Bütün insanların şirketi yoktur.
Şimdi bu classların kullanımını görelim.
Hiyerarşi yukarıda anlattığım gibidir.Genel mantık budur.Bu sistemi siz daha iyi geliştirebilirsiniz. Buraya kadar giriş niteliğinde bir tanıtım yaptık.Sonraki sayfada mevzuya birazdaha derinden girelim.Kalıtımın sistematik mantığını inceleyelim.
Önceki sayfalar da kalıtım konusuna giriş kıvamındaydı.Bu sayfada ise kalıtımın sistematik mantığını inceleyeceğiz.Şimdi bir emlakçı mantığıyla çalışan kiralık ve satılık evlerin kalıtımsal hiyerarşisini kuralım. Kiralık ve satılık evlerin ortak özelliklerini Ev.cs sınıfın da hazırlayalım.
---Ev.cs---
class Ev
{
public int OdaSayisi { get; set; }
public double Alani { get; set; }
public double Fiyati { get; set; }
public int Kati { get; set; }
public bool GarajVarmi { get; set; }
}
Aklıma geldiği kadar bir evin olağan özelliklerini yazdım.Şimdi kiralık evin classını oluşturalım.Kiralik.cs sınıfında hazırlayalım.
---Kiralik.cs---
class Kiralik:Ev
{
public int KontratSuresi { get; set; }
}
Şimdi de satılık evlerin classını oluşturalım.Satilik.cs sınıfında hazırlayalım.
---Satilik.cs---
class Satilik:Ev
{
public int EmlakciKomisyonu { get; set; }
}
Şimdi bu oluşturduğumuz ufak hiyerarşiyi oluşturmamın sebebi , kalıtımın işleyiş mantığını anlatmak için oluşturdum.
Şimdi Satilik.cs ya da Kiralik.cs’den nesne oluşturalım.
Kiralik kiralikev = new Kiralik();
Yukarıda bir adet Kiralik.cs sınıfından nesne yarattık.Aslında bu nesne yaratılmadan önce Base Class arka planda bir Ev nesnesi yaratır, içindeki propertyler set edilir,işlemleri yapılır daha sonra Kiralik.cs sınıfından nesne oluşturulur ve işlemleri yapılır.
Yani anlayacağınız bir sınıfın Base Classının constructorı her zaman Derived Classın constructorından önce çalışır.
Şimdi çalışma mantığı budur.Bu mantıkla haraket edersek olası bir kaç durum vardır onları sizlere açıklamak istiyorum.
Şimdi Ev.cs sınıfının constructorını değiştirelim.
---Ev.cs---
class Ev
{
public int OdaSayisi { get; set; }
public double Alani { get; set; }
public double Fiyati { get; set; }
public int Kati { get; set; }
public bool GarajVarmi { get; set; }
public Ev(string rastgeleparametrealsin) { }
}
Yukarıda gördüğünüz gibi Ev.cs sınıfının constructorını parametreli olarak değiştirdim.Şimdi bu durumda Kiralik.cs ya da Satilik.cs den bir nesne oluşturalım.(Kiralik.cs ve Satilik.cs sınıfları değiştirilmediği için yukarıdakilerin aynısıdır.)
Kiralik kiralikev = new Kiralik();
Bu nesneyi oluşturduktan sonra programımızı derlersek eğer hatayla karşılaşacağız.Program derlenmeyecektir.Aslında yazının bu satırına kadar okuduysanız sebebini biraz düşünüp bulabilirsiniz.
Bu hatanın sebebi,yukarılarda bahsettiğim gibi,Kiralik.cs sınıfından nesne oluşturulmadan önce,Base Class tan nesne oluşturulur.Ancak program akışı Base Class’a gelince parametreli constructordan başka bişey bulamayacaktır.Biliyoruz ki bir classa parametreli constructor yazınca ve boş constructor yazmayınca, mecbur o sınıftan nesne üretilirken o constructorın parametrelerine değerler gönderilmelidir.Çünkü boş constructor olmadığı için,mecbur o constructorı kullanmak zorunda kalıyoruz.
Bu sebepten dolayı Kiralik.cs den nesne oluşturulmadan önce Base Classında boş constructor ile nesne oluşturmaya çalışıyor.Ev.cs sınıfında boş constructor olmadığından ya da Kiralik.cs sınıfının boş constructorından Ev.cs içindeki başka bir constructor referans edilmediğinden dolayı hata oluşuyor.
Bu sorunun çözümü Ev.cs sınıfı içinde Kiralik.cs sınıfı ile uyumlu constructor yazmak gerekiyor.(Örnekteki çözüm Ev.cs sınıfına bir tane boş contructor yazmak yeterli olacaktır.)
Şimdi ise varsayalım ki , Ev.cs sınıfı içine Kiralik.cs ile uyumlu constructor yazmadık.Ancak Kiralik.cs sınıfından nesne oluştururken Base Classtaki parametreli constructorı kullanmayı görelim.
Kiralik.cs sınıfını şu şekilde düzenleyeceğiz.
---Kiralik.cs---
class Kiralik:Ev
{
public int KontratSuresi { get; set; }
public Kiralik(): base("RastgeleDeğer")
{ }
}
Yukarıda gördüğünüz gibi,Kiralik.cs ye bir constructor yazdım ve “:” operatörünü kullanarak “base” tagıyla Base Classtaki constructora değer gönderdim.base tagı,Base Classtaki constructorlara ulaşmamızı sağlıyor.(Örnek verdiğim projede Satilik.cs sınıfıda Ev.cs sınıfından kalıtım aldığı için aynı işlemleri ona uyguluyorum.)
Bu olası hataya düşerseniz şimdiden önlemini almak için bahsettim.
Şimdi bir sonraki sayfada virtual ve override kavramlarından bahsedeceğim.
Bu sayfada virtual ve override kavramlarına değineceğim.Bu kavramları ne gibi durumlarda ve niçin kullanacağız onları inceleyeceğiz.
Virtual: Eğer Base Class içindeki bir metod(işlev), Derived Classlarda farklı bir biçimde kullanılacaksa,o metod Base Class içinde virtual olarak tanımlanmalıdır.Böylece , bu classtan türeyen classlar, kendi içlerinde Base Class da virtual olarak belitilen metodları yeniden tanımlayabileceklerdir.
Override : Bir classa kalıtım yolu ile geçen ve virtual olarak tanımlanmış yapılar(metod,property) yeniden tanımlanıp farklı işlemler yapılabilir.(override yazıp bir boşluk bırakıyoruz.Sonra metod ya da property seçtikten sonra “Tab” tuşuna basıyoruz.)