override bağlamsal anahtar sözcüğü

Taban sınıfınızınız sanal bir işlevini ezerken (override) başınıza gelebilecek olanların farkında mısınız?

Base sınıfından türetilen Der sınıfının bildirdiği tüm işlevler Base sınıfının sanal işlevlerini ezmeye yönelik olsun:

Önce f1 işlevine bakalım. Taban sınıfın f1 isimli sanal işlevi double türden bir parametre değişkenine sahip. Der sınıfı bu işlevi ezmek istiyor. Ancak işlevi ezmek amacıyla işlevin bildirimini yaparken parametre değişkenini double türden yapmak yerine float türden yapmış. Eyvah ki eyvah! Ne bir sözdizim (syntax) hatası söz konusu ne de derleyiciyi mantıksal bir uyarı mesajı vermeye teşvik edecek bir durum var. Bu bir ezme işlemi değil ve ne yazık ki artık bu işlev için çalışma zamanı çokbiçimliği de söz konusu değil.

Yukarıdaki kodda global gf işlevine Der sınıfı türünden myder nesnesi gönderildiğinde gf içinde çağrılan işlev Base sınıfının f1 işlevi olacak, Der sınıfının değil. Yazımız ingilizce olsaydı belki şu kelime oyununu yapardık: We overwrite Base::f1.
Bu tür bir hata riskinin ciddiye alınması gerekiyor: Taban sınıfınızın bir sanal ya da saf sanal (pure virtual) işlevini ezmek için aynı imzaya ve aynı geri dönüş değeri türüne sahip bir işlev bildirmelisiniz. Eğer bildirdiğiniz işlevin geri dönüş değeri türü farklı fakat imzası farklı ise derleyici bu durumu kabul etmez. Yani bir sözdizim hatası oluşur. (Bu kuralın da ingilizcede variant return type denen bir istisnası var ama şimdi konuyu dağıtmayalım).
Ancak taban sınıfın sanal işleviyle aynı isme sahip fakat imzası farklı bir işlev bildirirseniz bu durum geçerlidir. Bunu yaparak  yeni bir işlev tanıtmış olursunuz.

Şimdi de Der sınıfının f2 işlevine bakalım. Der sınıfı bu kez taban sınıfın f2 isimli işlevini ezmeye çalışırken virtual anahtar sözcüğünü yazmış ancak const anahtar sözcüğünü bildirime eklemeyi unutmuş. Oysa const anahtar sözcüğü de imzanın bir parçası. Peki şimdi Der sınıfı Base sınıfının sanal f2 işlevini ezmiş oldu mu? Tabi ki hayır. Der sınıfı istemeden yeni bir sanal işlev zinciri başlatmış oldu. Artık Der sınıfından türetilecek yeni sınıfların da bu işlevi ezme hakkı var. Neye niyet neye kısmet. Derleyici bu durumda da sessizce işini yapacak.

Son olarak f3 işlevine de bir göz atalım. Taban sınıfın f3 isimli işlevi sanal olmadığı için bunu ezmek de söz konusu değil. Her programcı hata yapma eğiliminde olan bir canlıdır.   Kodlayıcımız bu işlevi de sanal sanmış ve ezmeye çalışmış.  Derleyiciden ne bir hata mesajı ne de bir uyarı mesajı gelecek.

Şimdi daha da tehlikeli bir duruma bakalım. Bu kez Base büyük bir sınıf hiyerarşisinin en tepesindeki taban sınıf olsun. Base sınıfından onlarca sınıf türetilmiş ve türetilen sınıfların hepsi Base sınıfının f1 sanal işlevini doğru şekilde ezmiş olsunlar. Base sınıfını yazan programcı f1 sanal işlevinin imzasını değiştiriyor:

Bu durumda Base sınıfından türetilmiş tüm sınıfların f1 işlevini ezen işlevlerinin de imzalarının değiştirilmesi gerekir değil mi? Eğer tek bir sınıf bile f1 işlevinin imzasını değiştirmez ise artık bu snıf f1 işlevini ezmiş olmayacak. Ve türemiş sınıfların kendi f1 işlevlerinin imzalarını değiştirmemeleri bir sözdizim hatası olmayacak. Yani derleyicinin bu değişiklik sürecinde bir desteği olmayacak.

C++11 ile gelen override anahtar sözcüğü bütün bu hata risklerini ortadan kaldırıyor.  Taban sınıfın bir üye işlevini ezerken bu niyetimizi derleyiciye açıkça iletmek için bildirimde override anahtar sözcüğünü kullanıyoruz:

Bir işlev override anahtar sözcüğüyle bildirildiğinde derleyici bu işlevin taban sınıfın bu imzalı bir sanal ya da saf sanal işlevinin var olup olmadığına bakar. Eğer böyle bir işlev yoksa durumu sözdizim hatası olarak işaretler.  Böylece yanlış bir ezme girişimi önlenmiş olur. Hemen şunu da ekleyim; bu amaçla böylesi bir anahtar sözcük kullanımı zaten diğer nesne yönelimli programlama dillerinin çoğunda vardı.  C++ bu noktada epeyce geç kaldı diyebiliriz.

override anahtar sözcüğü const ve noexcept anahtar sözcüklerinden sonra gelmeli:

override bir bağlamsal anahtar sözcük (contextual keyword). Bu şu demek: Eğer override sözcüğü bu anlamın dışında başka bir bağlamda kullanıldığında anahtar sözcük olarak ele alınmaz, bir isim (identifier) olarak değerlendirilir. Böylece C++11 öncesinde override sözcüğünü  isim olarak kullanan kodların C++11 sonrası üretilen derleyicilerde yeniden derlenmesi durumunda bir sorun olmuyor.

Kıssadan hisse: Taban sınıfın sanal ya da saf sanal bir işlevini ezdiğinizde mutlaka override anahtar sözcüğü kullanın.

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