kalıtımla alınan kurucu işlevler

Elimizde bir sınıf var ve biz bu sınıfın public arayüzünü genişletmek (extend) istiyoruz. Kalıtıma başvururuz değil mi?

Artık Der sınıfının müşterileri (clients) Der sınıf nesneleri için taban sınıftan devir alınan func ve foo işlevlerini çağırabilecekleri gibi Der sınıfının kendi public arayüzüne eklediği func işlevini de kullanabilecekler:

Ama bir sorun var. Türemiş Der sınıfı hiçbir kurucu işlev bildirilmediği için yukarıdaki kodda d1, d2 ve d3 nesnelerinin tanımları geçersiz. Yani taban sınıfınızın kurucu işlevleri otomatik olarak devralınmıyor. Peki ne yapmak gerekiyor? Türetilmiş sınıf taban sınıfın her bir kurucu işleviyle aynı imzalı birer kurucu işlev bildirecek ve bu işlevler aldıkları argümanları taban sınıfın ilgili kurucu işlevlerine pas edecekler:

Peki derleyici bunu bizim için kendi yapamaz mıydı? C++11 ile birlikte bu sorunun da yanıtı evet. Artık türemiş sınıflar taban sınıfların tüm kurucu işlevlerini kalıtım yoluyla devralabiliyorlar:

Birçok nesne yönelimli programlama dilinde zaten var olan C++11 standartlarıyla C++’a da eklenen bu özelliğe ingilizcede “inherited constructor” deniyor.

Kurucu işlevleri kalıtım yoluyla devir alırken dikkat etmemiz gereken bazı noktalar var:

Taban sınıfın varsayılan, kopyalayan ve taşıyan kurucu işlevlerini bu yolla alamıyoruz. Bu özellik kullanılmış olsa dahi, türemiş sınıf için bu işlevlerin yazılması gerekiyorsa derleyici bu işlevleri yazması gereken biçimde yazar.

Taban sınıfın kurucu işlevlerinin explicit ya da constexpr olması durumunda kalıtım yoluyla bu kurucu işlevlerin alınması durumunda türetilen sınıfların ilgili kurucu işlevleri de explicit ya da constexpr özelliklerine sahip olur. using bildirimiyle bu özellikler değiştirilemez.

Kalıtılmış kurucu işlevler türetilmiş sınıfın veri öğelerine ilk değer vermezler. Yani türetilmiş sınıfın kendi veri öğesi ya da öğeleri var ise ve bu öğelere ilk değer vermek istiyor isek bu özelliği doğrudan kullanamayız:

Der sınıfı türünden bir nesne hayata getirildiğinde bu nesnenin mx isimli static olmayan veri öğesine ilk değer verilmemiş olacak. İlk değer verilmeyen doğal türden veri öğelerinin çöp değerde kaldıklarını unutmayalım. Eğer türetilmiş sınıfın kendi eklediği bir öğe bir sınıf türünden ise bu öğe için varsayılan kurucu işlev çağrılır. Böylesi bir ilk değer verme istenmiyorsa bu durumda iki seçeneğimiz var: Ya bu özelliği hiç kullanmayacağız ya da türetilmiş sınıfın static olmayan veri öğelerine sınıf içinde ilk değer (in-class initializer) vereceğiz:

Taban sınıfın kurucu işlevlerinin kalıtım yoluyla devralınmasında ya hep ya hiç kuralı geçerli. Yani

bildirimiyle taban sınıfın istisnasız tüm kurucu işlevlerini alıyoruz. Taban sınıfın kurucu işlevlerinin bir kısmını almak bir kısmını almamak gibi bir seçeneğimiz yok.

Türemiş sınıfın taban sınıfın kurucu işlevlerini kalıtım yoluyla devralması kendisinin yeni kurucu işlevler bildirmesine bir kısıtlama getirmez. Hatta türemiş sınıf taban sınıfın kurucu işleviyle aynı imzalı bir kurucu işlev de bildirebilir. Bu durumda türemiş sınıfı  kurucu işlevi taban sınıfın aynı imzalı kurucu işlevini gizler:

using bildirimi türemiş sınıfın hangi erişim özellikli bölgesinde yapılırsa yapılsın taban sınıfın kurucu işlevlerinin erişim özellikleri korunur. Örneğin taban sınıfın kurucu işlevi  protected ise kalıtım yoluyla türemiş sınıf tarafından devralınan kurucu işlev de türemiş sınıfın  protected öğesidir. Oysa taban sınıfın kurucu işlev olmayan diğer protected işlevleri bir using bildirimiyle türemiş sınıfın public ara yüzüne katılabilir:

Taban sınıfın kurucu işlevlerinin varsayılan argümanları varsa varsayılan argümanlar devralınmaz. Bu durumda türemiş sınıf birden fazla kurucu işleve sahip olacaktır:

Der sınıfı içinde yapılan using bildirimiyle Der sınıfı şu kurucu işlevlere sahip olacaktır:

Peki, bu özellik çoklu türetmede de (multiple inheritance) kullanılabilir mi? Tabi ki evet. Eğer bir sınıfı çoklu türetme yoluyla birden fazla taban sınıftan türetiyorsanız her bir taban sınıfın kurucu işlevlerini kalıtım yoluyla alabilirsiniz:

Ancak birden fazla taban sınıfın aynı imzalı kurucu işlevini kalıtım yoluyla almak geçerli değil:

Eğer kurucu işlevleri kalıtım yoluyla alınacak birden fazla taban sınıfın aynı imzalı kurucu işlevleri varsa, türemiş sınıf da aynı imzalı bir kurucu işlev bildirmek zorunda. Yukarıdaki kodda MDer sınıfının aşağıdaki biçimde tanımlanması geçerli olurdu:

Son söz: Yaşasın C++11!

Necati Ergin

C ve Sistem Programcıları Derneğinde eğitmen olarak çalışıyor.

Bunlar da ilginizi çekebilir

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Kod Eklemek İçin Okuyun