Tip Dönüştürme Nedir
Tip dönüştürme, bir değeri bir tipten başka bir tipe çevirmek demektir: bir double'ı int'e, bir char'ı sayısal koduna veya bir taban sınıf işaretçisini türetilmiş bir işaretçiye dönüştürmek. C++ bu dönüşümlerin bir kısmını senin için otomatik yapar, ama sessizce yaptıkları tam olarak hataların saklandığı yerdir.
İki tür vardır: kendiliğinden gerçekleşen örtük dönüşümler ve senin açıkça yazdığın belirtik cast'ler. Bunun bir belirtisiyle operatörler konusunda zaten karşılaştın: tam sayı bölmesi. Cast, bunun kontrolünü ele almanın yoludur.
Örtük Dönüşümler
Bir ifadede sayı tiplerini karıştırdığında, C++ iki taraf da eşleşsin diye "küçük" tipi "büyük" olana yükseltir. Bu genellikle istediğin şeyi yapar.
Sorun, dönüşüm ters yöne gittiğinde başlar: daha geniş bir tipten daha dar bir tipe. Bu bir daraltma dönüşümüdür ve sessizce veri kaybedebilir.
Float'tan int'e dönüşüm sıfıra doğru keser: yuvarlamaz, bu yüzden 3.99, 3 olur. Ve 300'ü bir char'a tıkıştırmak taşmaya yol açar. Birçok derleyici burada uyarır; bazıları uyarmaz. Gerçekten daraltmak istediğinde, bir sonraki okuyucu bunun bilerek yapıldığını bilsin diye bir cast ile açıkça belirt.
Tam Sayı Bölme Tuzağını Düzeltmek
Cast yapmanın en yaygın nedeni bölmedir. Her iki operand da tam sayı olduğunda, / tam sayı bölmesi yapar ve kalanı atar.
Çözüm, bölmeden önce bir operanda static_cast<double> uygulamaktır. Sık yapılan bir hata static_cast<double>(got / total)'tır; bu çok geçtir, çünkü cast çalıştığında got / total zaten 0'dır, dolayısıyla 0.0 alırsın. Sonucu değil, bir operandı dönüştür.
static_cast: Varsayılan Cast'in
C++ sana adlandırılmış dört cast verir. Zamanın %95'inde kullanacağın, ilişkili tipler arasında iyi tanımlanmış dönüşümler yapan static_cast<T>(value)'dır: sayısal dönüşümler, enum'dan int'e, void*'tan tipli bir işaretçiye geri dönüş ve tipi zaten bildiğinde bir sınıf hiyerarşisinde yukarı/aşağı geçiş.
Eski C tarzı cast (int)balance yerine static_cast'i tercih et. Bir C tarzı cast, kodun derlenmesi için herhangi bir dönüşümü dener; aşağıdaki tehlikeli olanlar dahil, dolayısıyla sessizce const'u kaldırabilir veya ham baytları yeniden yorumlayabilir. static_cast yalnızca derleyicinin gerçekten gerekçelendirebildiği dönüşümlere izin verir ve uzun static_cast<...> ifadesini bir kod incelemesinde aramak çok kolaydır.
// Kaçın - C tarzı cast, güvenlik ağı yok:
int dollars = (int) balance;
// Tercih et - belirtik, denetlenmiş, aranabilir:
int dollars = static_cast<int>(balance);
Diğer Üç Cast (Tutumlu Kullan)
Geriye kalan cast'ler belirli, dar işler için vardır. Onlara yalnızca static_cast gerçekten yapamadığında başvur.
const_cast, const'u kaldırır (veya ekler). Tek meşru kullanımı, bir parametreyi const olarak işaretlemeyi unutmuş bir C tarzı API'yi çağırmaktır. Aslında const olarak bildirilmiş bir nesneyi bir const_cast üzerinden değiştirmek tanımsız davranıştır.
void legacyApi(char* msg); // eski API, const almıyor
const char* text = "hello";
legacyApi(const_cast<char*>(text)); // yalnızca legacyApi ona yazmıyorsa sorun yok
reinterpret_cast, ham bit deseni yeniden yorumlar; örneğin bir işaretçiyi tam sayı bir adres olarak. Hiçbir dönüşüm yapmaz ve son derece güvensizdir; neredeyse her zaman tasarımı yeniden düşünmen gerektiğinin bir işaretidir.
dynamic_cast, bir taban sınıf işaretçisini veya referansını, nesnenin gerçek tipini kullanarak çalışma zamanında türetilmiş bir tipe güvenle dönüştürür. Polimorfik bir taban gerektirir (en az bir virtual fonksiyona sahip bir sınıf) ve cast uygulanmazsa nullptr döndürür.
Eğer a başka bir Animal'a işaret etseydi, dynamic_cast<Dog*> nullptr döndürür ve else dalı çalışırdı; tam da bu yüzden bir hiyerarşide aşağı inmek için körü körüne static_cast kullanmaktan daha güvenlidir.
Kaçınılması Gereken Yaygın Hatalar
- Operand yerine sonucu dönüştürmek.
static_cast<double>(a / b)önce kesrini atar.a'yı veyab'yi dönüştür. - Float'tan int'e yuvarladığını varsaymak. Keser:
static_cast<int>(2.99)2'dir. Yuvarlama içinstd::round,std::lroundvb. kullan. - C tarzı bir cast'e başvurmak. Hangi dönüşümün gerçekleştiğini gizler.
static_castkullan; dönüşüm güvensiz olduğunda sessiz bir sürpriz yerine derleme hatası alırsın. - Çok küçük bir tipe daraltmak.
300'üchar'a veya devasa birlong'uint'e dönüştürmek sarar ya da taşar. Aralık için yeterince geniş bir hedef tip seç.
Sırada: If-Else
Artık değerleri temiz bir şekilde dönüştürüp karşılaştırabildiğine göre, sıradaki adım onlarla karar vermek. if-else ifadesi, bir koşulun true olup olmamasına bağlı olarak farklı kod çalıştırır; her dallanan programın temeli.
Sıkça Sorulan Sorular
C++'ta static_cast ile C tarzı cast arasındaki fark nedir?
(int)x gibi bir C tarzı cast her dönüşümü sırayla dener; sessizce tehlikeli bir reinterpret_cast'e dönüşebilir veya const'u kaldırabilir. static_cast<int>(x) yalnızca derleyicinin doğrulayabildiği ilişkili dönüşümleri yapar, böylece derleyici saçmalıkları reddeder. Modern C++'ta her zaman C tarzı cast'ler yerine static_cast'i tercih et; daha güvenlidir ve grep ile aramak çok daha kolaydır.
C++'ta bir int'i double'a nasıl dönüştürürüm?
static_cast<double>(x) kullan. Bu en çok bölmede önemlidir: 5 / 2 tam sayı bölmesidir ve 2 verir, ama static_cast<double>(5) / 2 2.5 verir. Bölme gerçekleşmeden operandlardan birini dönüştür; sonucu dönüştürmek, static_cast<double>(5 / 2), çok geçtir ve yine 2.0 verir.
C++'ta büyük bir değeri daha küçük bir tipe dönüştürmek neden yanlış bir sayı verir?
Değeri tutamayan bir tipe dönüştürmek bir daraltma dönüşümüdür. Float'tan int'e kesirli kısım atılır (static_cast<int>(3.99) 3'tür) ve aralık dışı bir tam sayı ya sarılır (işaretsiz) ya da uygulamaya bağlı olur (işaretli). Derleyici genellikle seni durdurmaz, bu yüzden dönüşümü bilinçli yap ve hedef tipin yeterince geniş olduğundan emin ol.