1- Giriş

Çalışma zamanında tür belirleme (RTTI-real time type identification) bir maliyeti vardır.  RTTI kullanımı için derleyiciler kendilerine özgü kodlamaları olur, ama sabit olan şey bellekte her bir veri türü için type_info sınıfı için yer ayırmasıdır. Evet doğru okudunuz, tanımlanan her nesne için bir de type_info sınıfı tanımlanmış olur. Sistemlerin çoğunda, çok biçimli her nesne bu nesne için ayrılmış bellek alanında, ait olduğu çok biçimli sınıfa ilişkin tutulan sanal işlev tablosunun adresini tutan bir göstericiye sahiptir. Yukarıdaki grafik bunu göstermektedir. Yani türetme işlemi yapıldığında RTTI mekanizmasının kullanılabilmesi için bellekte type_info sınıf için yer açılır. 

Her veri türü için bir type_info nesnesinin var olması özellikle büyük programlar için fazladan yük getirir. Yüzlerce çok biçimli sınıfa sahip bir programda yine yüzlerce type_info nesnesi yaratılır, bu nesneler bellekte yer kaplar. Bütün sınıf nesneleri gibi type_info sınıfı nesnelerinin de yaratılmasının da zamansal bir maliyeti söz konusudur. RTTI program içinde hiç kullanılmamış olsa da type_info nesneleri yine yaratılır.

Yukarıdaki paragrafta aslında problemin en temeli açıklanıyor. Yüzlerce kullanılmayan ve bellekte yer kaplayan type_info sınıfı. Embedded işlerde bu durum oldukça önemli bir konu olur. Bellekte yer kaplamasının dışında yavaşlığa de sebep olur.

2- typeid İşleci ile dynamic_cast Maliyet Açısından Karşılaştırılması

C++ dilinde runtime esnasında bir nesnenin türü belirlenebilir. typeid işlecinin bir değer üretmesi her nesne için “sabit” bir süre içinde gerçekleşir. Süre her çok biçimli nesne için, türetme sınıf hiyerarşisi içinde yeri ne olursa olsun sabittir ve bu süre bir sanal işlevin çağrısı için harcanan süreye eşdeğer kabul edilebilir.

Ancak dynamic_cast için geçen süre sabit bir süre değildir. dynamic_cast<T *>(base_ptr) gibi bir ifadenin değerlendirilmesi için geçen süre, dönüştürülme işlemine sokulan sınıfın ait olduğu sınıf hiyerarşisinin derinliğinin artmasıyla artar. Yukarıdaki ifadede base_ptr göstericisinin ait oldugu sınıfın çok derin bir türetme zincirinin en tepesindeki sınıf olduğunu düşünelim. Dönüştürülmenin yapılacağı tür de sınıf hiyerarşisi içinde yer almayan bir tür olsun. dynamic_cast işlecinin NULL adresi üretmesi için türetme zincirinin en alt kademesine kadar gidip kontrol etmesi gerekir. Sonuç tasarım açısından dynamic_cast işleci typeid işlecine göre tercih edilmelidir, çünkü dynamic_cast işleci ile oluşturulan kodun esnekliği ve geliştirilebilirliği type_id işleci ile oluşturulmuş koda göre daha fazladır. Ancak buna karşı dynamic_cast işlecinin maliyeti de typeid işlecinin maliyetine göre daha fazladır.

3- Çalışma Zamanında Tür Belirlenmesinin Sakıncaları

Sanal işlev yapısı, her zaman RTTI araçlarına tercih edilmelidir. RTTI araçlarının bir zorunluluk bulunmamasına karşın kullanılması programların karmaşıklığını arttırır, test işlemlerini zorlaştırır. Kaynak kod değişikliklere karşı daha kırılgan hale gelir. Programın çalışması yavaşlayabilir. Yani kısaca RTTI kullanmaktan kaçınılmalı ve sanal işlev yapıları tercih edilmelidir. Ama eğer RTTI kullanma zorunluluğu var ise de dynamic_cast tercih edilmelidir.

 İyi bir tasarımda yalnızca zorunlu durumlarda RTTI kullanılmalıdır. Peki dinamik tür kontrolünün yapılmasında tasarım açısından sorunlu olan durum nedir?
1. Aşağı doğru dönüşümler karmaşıklığın hizmet veren kodlardan hizmet alan kodlara yani kullanıcı kodlarına kaydırılmasına neden olurlar. Böylece kodların karmaşıklığı artar, buda kodlama maliyetinde bir artışa neden olur.
2. Karmaşıklığın kullanıcı kodlarına kayması kodların genel olarak büyümesine neden olur.
3. Dönüşümün güvenli olup olmadığını sınamak için her dönüşüm için ayrı bir kod yazmak gerekir.
4. Bu dönüşümler programın çalışmasında genel bir yavaşlamaya neden olurlar. Yavaşlama oranı da sabit değildir, sınıf hiyerarşisinin derinliği oranında artar.
5. Programın yapılacak eklemeler zorlaşır. Çoğu zaman, türetme hiyerarşisine eklenen sınıflar için ek testler ya da kontroller yapmak gerekir.

Ana sorun daha önce yazılmış bir kod parçasına ulaşabilmek için, fazladan bir kod yazma zorunluluğudur. Üstelik fazladan yazılan kod, programın genişletilmesi amacında daha sonradan sorunlara yol açabilir. Fazladan yazılan kod, bir sınıf türü için çalışma zamanında, o sınıf türü için belirli işlevlerin çağırılıp çağırılamayacağını sınamak için yazılan kodlardır. Ek kod içinde yapılan sınama olumlu sonuçlanırsa aşağı doğru bir dönüşüm yapılarak, istenen işlev çağrılır. Eğer daha önce yazılmış olan bir kodu (server code) bulmak için programcı ek bir kod yazmış ise, programcının yazmış olduğu ek kod karmaşıktır ve çeşitli hatalara açıktır. Oysa nesne yönelimli programlama tekniğinin ana özelliklerinden birisi karmaşıklığı indirgemektir. Dinamik tür kontrolünun uygulandığı çoğu durumda programcının, ana kodda oluşturulan türetme hiyerarşisi hakkında bilgi sahibi olmasını zorunlu kılar, bu durumda da ileride ana kodda kullanılan sınıf hiyerarşisi yapısında bir değişiklik yapıldığında, yazılan kodların geçersiz bir duruma düşmesine ve tekrar yazılmak zorunda kalınmasına neden olabilir.

4- Aşağı Doğru Dönüşümlere Seçenek: Sanal İşlevler

RTTI araçlarını ve aşağı doğru dönüşümleri (downcast) kullanmaya birinci seçenek, dinamik bağlamanın ve sanal işlevlerin kullanılmasıdır. Bu teknikte, yalnızca türemiş sınıflarda kullanılacak üye işlevler genelleştirilerek taban sınıfa kaydırılırlar. Yani kullanıcı kodları, sanal işlevler biçiminde nesnenin içine kaydırılır. Bu durumda aşağı doğru dönüşümler derleyiciler tarafından otomatik olarak ve güvenli bir şekilde yapılırlar. Aşağı doğru yapılan bir dönüşüm eğer güvenilir değilse zaten derleme aşamasında derleyici tarafından saptanır. Ayrıca bu tür bir tasarım, söz konusu programın geliştirilebirliği konusunda da son derece esnek bir yapı sağlar, yeni bir türetme yapılması durumunda var olan ana sınıf kodlarında bir değişiklik yapılması gerekmez. Aşağı doğru dönüşüm ve izleyen if deyiminden oluşan kod parçacıkları çoğu zaman, sanal işlev çağrılarıyla değiştirilebilirler. Buradaki anahtar faktör, yetenek sorgulamasının bir hizmet isteğine dönüştürülmesidir. Nesneye yapılan bir hizmet alma isteği bir sanal işlev çağrısıdır.

Derleyici ayarlarından RTTI mekanizmasının devre dışı bırakılması, çalışabilir kodun küçülmesine ve çalışma hızının artmasına neden olur. Bu sayede RTTI kullanımını kapatmış oluruz.

Son olarak yukarıdaki notaları aldığım kaynaklardan son söz:

C++ dilinde Nesne Yönelimli Programlama Tekniği kullanılarak yazılmış programlarda, program tasarımı, diğer programlama dillerinde olduğundan çok daha fazla öneme sahiptir.

Pdf olarak indir.