operator bool işlevi

Bazı durumlarda sınıf nesnelerimizin lojik ifade beklenen yerlerde lojik yorumlamaya tabi tutulmasını isteriz. Örneğin nesneleri sayaç olarak kullanılacak Counter isimli bir sınıfımız olsun:

Yukarıdaki kodda Counter türünden c isimli nesnenin lojik yorumlama beklenen bir yerde, if parantezi içinde kullanıldığını görüyorsunuz. Bu C++ dilinin kurallarına aykırı. Eğer Counter sınıfının lojik yorumlamayı gerçekleştirebilecek bir tür dönüştürme operatör işlevi olsaydı derleyici otomatik olarak (implicitly) bu işlevi çağıracaktı. Şimdi sınıfa bu amaçla yazılan ve Counter sınıfı nesnelerini bool türüne dönüştüren bir tür dönüştürme operatör işlevinin eklendiğini düşünelim:

Derleyici bu durumda if parantezi içindeki ifadeyi bu işleve yapılan çağrıya dönüştürecek:

Önce tür dönüştürme operatör işlevleri konusunda bazı hatırlatmalar yapalım:
Tür dönüştürme işlevleri global olarak yüklenemiyor. Yani bu işi gerçekleştirecek işlevlerin sınıfın üye işlevleri olması zorunlu.
Bu işlevlerin bildirimlerinde ya da tanımlarında geri dönüş değerlerinin türleri yazılmıyor. Bu durum geri dönüş değerlerinin olmadığı anlamına gelmiyor. Zaten işlevin adı işlevin geri dönüş değerinin türünü belirtiyor. Geri dönüş değeri türü yazılsaydı (yazılması sentaks hatası) şöyle bir görüntü olacaktı:

Tür dönüştürme operatörü doğal türler için kullanıldığında terimi (operand) olan nesneyi değiştirmiyor. Bu yüzden tipik olarak bu işleci yükleyen işlev sınıfın const üye işlevi yapılıyor.

C++11 öncesinde bool türüne dönüşüm yapan bir işlev çok tercih edilen bir yapı değildi. Çünkü bu işlev, normalde geçerli olmaması gereken ve istenen yanlışlıkla yazılmış bazı kodların geçerli kılınmasına neden oluyordu. Aşağıdaki koda bakalım:

kodda yer alan

deyiminin yanlışlıkla yazıldığını düşünelim. Ama kod geçerli. Derleyici bu işlemi yapabilmek için Counter türünden olan c1 isimli nesneyi, sınıfın tür dönüştürme işlevini çağırarak bool türüne dönüştürecek. bool türünden de double türüne standart dönüşüm gerçekleştirilecek. Yani derleyicinin ürettiği kodu biz isteyerek ve bilinçli olarak yazmak isteseydik şöyle bir deyim yazacaktık:

Şimdi de func işlevi içinde yer alan diğer deyime bakalım:

Bu deyimin de yanlışlıkla yazıldığını düşünelim. Bu kod da geçerli. Derleyici çarpma işleminin yapılabilmesi için işlecin her iki terimini de sınıfın operator bool işlevini kullanarak bool türüne dönüştürecek. Ardından da işlecin terimleri, bool türünden tamsayıya yükseltme (integral promotion) dönüşümüyle int türüne dönüştürülecek ve çarpma işlemi int türünde yapılacak. Böyle bir işlemin yapılması istenseydi tür dönüştürme işleç kullanımı ile açıkça yapılırdı:

Peki bu soruna C++11 standartları ile bir çözüm getirilmeden önce ne yapılıyordu? Çözümlerden biri bool türüne dönüştürme yapan bir işlev yerine void * türüne dönüştürme yapan bir işlev tanımlamaktı:

Bu duruma lojik ifade gereken yerlerde sınıfın operator void * işlevi çağrılacak. Ancak void * türünün kullanılmasının geçersiz olduğu yerlerde derleyici tarafından içsel bir dönüşüm uygulanmayacak:

Yukarıdaki koddan da görebileceğiniz gibi void * türüne dönüştüren işlev de sorunumuzu tam olarak çözmüyor. Counter türünden bir nesnenin delete işlecinin terimi yapılması geçerli. Derleyici bu durumda tür dönüştürme işleviyle Counter nesnesini void * türüne dönüştürecek. Yine bir Counter nesnesinin bir adresle karşılaştırılması durumunda nesnemiz void * türüne dönüştürülecek.

Peki, yalnızca lojik ifade gereken yerlerde bir sınıf nesnesinin bool türüne dönüştürülmesi, bunun dışındaki diğer bağlamlarda bu dönüşümün geçersiz kılınması mümkün mü? C++11 öncesinde C++ programcıları bu amaçla “güvenli bool idiyomu” (safe bool idiom) denen bir yapıyı kullanıyorlardı. C++dilinin bazı araçlarını çok güzel gösteren bir koda sahip bu idiyomu bir başka yazımızda ele alacağız. Ancak bu idiyomu artık kullanmamıza gerek yok. C++11 standartlarıyla gelen bir özellik sorunumuzu mükemmel bir şekilde çözüyor.
Dönüştüren kurucu işlev (conversion constructor) gibi artık tür dönüştürme işlevleri de explicit olarak tanımlanabiliyor.

Bir tür dönüştürme işlevi explicit anahtar sözcüğüyle bildirildiğinde otomatik (implicit) dönüşüme izin vermiyor. Bu durumda tür dönüştürme yalnızca static_cast işleciyle açık (explicit) olarak yapılabiliyor. Ancak operator bool işlevi için güvence altına alınan bir durum daha var: Lojik ifade gereken bir bağlamda işlevimiz explicit olsa da yine de tür dönüşümüne izin veriliyor. Mükemmel çözüm!
explicit anahtar sözcüğü eğer işlevin bildiriminde yazılmış ise işlevin tanımında yer alamıyor. Dönüştüren kurucu işlevlerde de kuralın aynı olduğunu hatırlayalım.
Tür dönüştürme işlevlerinin explicit olabilmesi özelliği C++11 standartlarıyla dile eklenince standart kütüphane de bundan nasibini aldı. C++03’de std::ostream ve std::istream sınıf nesnelerinin lojik bağlamda kullanılmasını sağlamak amacıyla bu sınıfların void * türüne dönüştüren işlevleri vardı. C++11 ile birlikte bu işlevler kaldırıldı. Şimdi bu sınıfların explicit olarak bildirilen operator bool işlevleri var. Aşağıdaki koda bakalım:
while parantezi içinde çağrılan istream sınıfının operator>> işlevinin cin nesnesini referans yoluyla geri döndürdüğünü biliyorsunuz. Geri dönüş değeri olan cin nesnesi için derleyici sınıfın explicit operator bool işlevini çağırıyor:

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