https://github.com/deryaxacar/42-cpp_06
In this module, you'll learn about type conversions in C++ using operators like static_cast, dynamic_cast, and reinterpret_cast. You'll also explore polymorphism and safely convert between derived classes using dynamic_cast.
https://github.com/deryaxacar/42-cpp_06
42 42-cpp 42-cpp-module 42-cpp-modules 42-school 42born2code 42cursus 42projects 42school casting cpp cpp-all cpp-modules-42 cpp06 cppmodules typecasting
Last synced: about 2 months ago
JSON representation
In this module, you'll learn about type conversions in C++ using operators like static_cast, dynamic_cast, and reinterpret_cast. You'll also explore polymorphism and safely convert between derived classes using dynamic_cast.
- Host: GitHub
- URL: https://github.com/deryaxacar/42-cpp_06
- Owner: deryaxacar
- Created: 2025-02-15T16:10:15.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-02-21T17:58:04.000Z (2 months ago)
- Last Synced: 2025-02-21T18:34:42.528Z (2 months ago)
- Topics: 42, 42-cpp, 42-cpp-module, 42-cpp-modules, 42-school, 42born2code, 42cursus, 42projects, 42school, casting, cpp, cpp-all, cpp-modules-42, cpp06, cppmodules, typecasting
- Language: C++
- Homepage: https://github.com/deryaxacar/42-Cpp_06
- Size: 177 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
C++ Module 06
![]()
Bu modülde, C++'ta farklı cast türlerini öğrenerek tür dönüşümlerinin nasıl çalıştığını keşfedeceksiniz. static_cast, dynamic_cast ve reinterpret_cast gibi dönüşüm operatörlerini kullanarak veri türleri arasında güvenli ve etkili geçişler yapmayı öğreneceksiniz. Ayrıca, dynamic_cast ile polymorphism kavramını daha iyi anlayarak, türetilmiş sınıflar arasında güvenli dönüşümler gerçekleştireceksiniz.### İçindekiler 📚
- [Ex00 - Conversion of scalar types](#conversion-of-scalar-types)
- [Ex00 - Gereksinimleri](#ex00-gereksinimleri)
- [Static Cast Nedir?](#static-cast-nedir)
- [Şablon (Template) Nedir?](#template-nedir)
- [NaN (Not a Number) ve Inf (Infinity) Nedir?](#nan-inf)
- [Numeric Limits Nedir?](#numeric-limits-nedir)
- [Ex01 - Serialization](#serialization)
- [Ex01 - Gereksinimleri](#ex01-gereksinimleri)
- [Static Metod Nedir?](#static-metod)
- [Reinterpret Cast Nedir?](#reinterpret-cast-nedir)
- [Uintptr_t Nedir?](#uintptr_tnedir)
- [Ex02 - Identify real type](#identify-real-type)
- [Ex02 - Gereksinimleri](#ex02-gereksinimleri)
- [Dynamic Cast Nedir?](#dynamic-cast-nedir)
- [Tür Dönüştürme Operatörleri Tablo](#tablo)---
## Ex00 - Conversion of scalar typesBu egzersizde, C++'ta bir sınıf `ScalarConverter` oluşturacak ve bu sınıfın yalnızca bir `statik` metodunu yazacaksınız: convert. Bu metod, bir C++ literal'inin `string` temsilini alacak ve şu dört `scalar` türüne dönüştürecektir:
- `char`
- `int`
- `float`
- `double`- **Sınıf Özellikleri:**
- `ScalarConverter` sınıfı instansiyalanamaz (kullanıcılar tarafından örneği oluşturulamaz). Bu, yalnızca `statik` metod convert kullanılarak işlem yapılması gerektiği anlamına gelir.
- **Metod:**
- `convert` `statik` metodu, `string` parametre olarak bir C++ literal’ini alacak ve bu değeri uygun türlerdeki değerlere dönüştürecektir.- **Dönüşüm Türleri:**
- `char`: Verilen değerin karakter türüne dönüştürülmesi.
- `int`: Verilen değerin tam sayı türüne dönüştürülmesi.
- `float`: Verilen değerin kayan nokta türüne (`float`) dönüştürülmesi.
- `double`: Verilen değerin çift hassasiyetli kayan nokta türüne (`double`) dönüştürülmesi.
- **Özel Durumlar:**
- **Char için:** Geçerli olmayan karakterler (görüntülenebilir olmayanlar) için bir hata mesajı gösterilecek.
- **Pseudo literals:** `-inff`, `+inff`, `nanf` gibi değerler de işlenmeli.
- **Dönüşüm Hataları:** Eğer dönüşüm mümkün değilse veya taşma durumu söz konusuysa, kullanıcıya bilgi veren bir mesaj yazdırılmalıdır.
- **İzin verilen Fonksiyonlar:**
- String'den bir sayıya dönüşüm yapan her türlü fonksiyon kullanılabilir (örneğin, `std::stoi`, `std::stof`, `std::stod`).
- **Test Programı:**
- `ScalarConverter` sınıfını test etmek için bir program yazılacaktır. Bu programda, kullanıcıdan alınan input, uygun türe dönüştürülecek ve her bir türdeki değer ekrana yazdırılacaktır.
- ```sql
./convert 0
char: Non displayable
int: 0
float: 0.0f
double: 0.0
./convert nan
char: impossible
int: impossible
float: nanf
double: nan
./convert 42.0f
char: '*'
int: 42
float: 42.0f
double: 42.0```
---
`static_cast` C++ dilinde kullanılan bir tür dönüşüm operatörüdür. Derleme zamanında, türler arasında güvenli dönüşümler yapılmasını sağlar ve özellikle temel türler arasında dönüşümde kullanılır. `static_cast`, derleyici tarafından kontrol edilen ve hatasız dönüşümler sağlar, fakat yanlış bir dönüşüm yapılması durumunda derleme hatası alınır.
**Temel Özellikler:**
- **Derleme Zamanı Dönüşümü:** `static_cast`, dönüşüm işlemlerini derleme zamanında gerçekleştirir. Bu, dönüşümün tür güvenliğini sağlamak anlamına gelir ve hata yapma olasılığını azaltır.
- **Basit Dönüşümler:** Genellikle türler arasındaki temel dönüşümleri (örneğin, `int`'ten `float`'a, `double`'dan `int`'e) yapmak için kullanılır.
- **Veri Kaybı:** Dönüşüm sırasında veri kaybı yaşanabilir (örneğin, `double`'ı `int`'e dönüştürmek). Bu nedenle dikkatli kullanmak gerekir.
**Kullanım Alanları:**
- **Temel Veri Türleri:** `static_cast`, genellikle `char` ve `int` gibi temel veri türleri arasında dönüşüm yapmak için kullanılır.
- **Sınıflar Arasında Dönüşüm:** Aynı sınıf hiyerarşisine sahip nesneler arasında dönüşüm yapmak için de kullanılabilir. Ancak, bu durumda daha dikkatli olmak gerekmektedir.
**Örnek Kullanım:**
- ```cpp
char ScalarConverter::toChar(int value) {
// int türündeki 'value' değişkenini char türüne dönüştür
char c = static_cast(value);
// Eğer değer char aralığının dışındaysa, dönüştürme mümkün değil
if (value > numeric_limits::max() || value < numeric_limits::min())
cout << "char: impossible" << endl;
// Eğer karakter ekranda gösterilebilir bir karakter değilse
else if (!isDisplayableChar(c))
cout << "char: Non displayable" << endl;
// Geçerli ve gösterilebilir bir karakterse, ekrana yazdır
else
cout << "char: '" << c << "'" << endl;
return c;
}
```---
C++'da şablonlar (`templates`), farklı veri türleriyle çalışabilen genel (`generic`) fonksiyonlar veya sınıflar yazmanızı sağlayan bir özelliktir. Şablonlar, kodunuzu daha esnek ve yeniden kullanılabilir hale getirir. Örneğin, aynı işlemi `int`, `double`, `string` gibi farklı türlerle yapmanız gerekiyorsa, her tür için ayrı fonksiyonlar yazmak yerine tek bir şablon kullanabilirsiniz. Şablonlarla ilgili daha detaylı bilgi için [Cpp 07](https://github.com/deryaxacar/42-Cpp_07) repoma göz atabilirsiniz.
---
### NaN (Not a Number) ve Inf (Infinity) Nedir?Bu iki kavram, bilgisayar bilimlerinde `IEEE 754` (kayan noktalı sayıların (floating-point numbers) bilgisayarlarda nasıl temsil edileceğini belirleyen uluslararası bir standarttır.) standardına dayalı kayan noktalı sayıların temsilinde kullanılır.
**1. NaN (Not a Number)**
- **Tanım:** Matematiksel olarak tanımsız işlemlerin sonucudur.
- **Oluşma Durumları:**
- `0.0 / 0.0` (Sıfırın sıfıra bölünmesi)
- `sqrt(-1)` (Negatif bir sayının karekökü)
- `log(-1)` (Negatif bir sayının logaritması)
- `inf - inf` (İki sonsuzun farkı)
- **Özellikler:**
- `NaN` eşitlik karşılaştırmalarında bile kendisiyle eşit değildir `(nan == nan → false)`.
- `IEEE 754` standardı, NaN değerinin belirli bir bit deseniyle temsil edilmesini sağlar.**2. Infinity (∞ - Sonsuzluk)**
- **Tanım:** Çok büyük veya çok küçük sayıların matematiksel limiti aştığında ortaya çıkar.
- **Oluşma Durumları:**
- `pozitif_sayı / 0.0 → +∞` (pozitif sonsuz)
- `negatif_sayı / 0.0 → -∞` (negatif sonsuz)
- `exp(1000)` gibi büyük bir hesaplama (overflow durumu)
- **Özellikler:**
- Sonsuzluk, aritmetik işlemlerle taşma (overflow) yaşandığında ortaya çıkar.
- `inf + 1 == inf` veya `inf * 2 == inf` gibi işlemler yine sonsuzluk üretir.
- `1.0 / inf == 0.0` olur.---
**NaN ve Inf İçin Kod İçindeki Kullanım**
- **NaN** değerleri için `"nan"`, `"-nan"`, `"nanf"`, `"-nanf"` gibi girdiler kontrol ediliyor ve `"impossible"` çıktısı veriliyor.
- **Infinity** (sonsuzluk) değerleri için `"inf"`, `"-inf"`, `"inff"`, `"-inff"` girdileri işlenerek `float` ve `double` çıktıları basılıyor.---
`numeric_limits`, sayı türlerinin sınırlarını sorgulamak için kullanılan bir şablon sınıfıdır. Bu sınıf, bir türün alabileceği en küçük ve en büyük değeri, hassasiyet gibi özellikleri verir. Özellikle sayısal hesaplamalarda taşma (overflow) veya hassasiyet kontrolü için kullanılır.
**Temel Özellikleri:**
- **`Minimum` ve `Maksimum` Değerler**: numeric_limits sınıfı, belirli bir türün alabileceği en küçük ve en büyük değerleri döndüren metotlar sunar.
- `std::numeric_limits::min()` — Türün alabileceği en küçük değeri verir.
- `std::numeric_limits::max()` — Türün alabileceği en büyük değeri verir.
- **Epsilon**: Sayısal hassasiyetle ilgili bir değer sağlar. Örneğin, `std::numeric_limits::epsilon()` fonksiyonu, float türünün en küçük pozitif farkını verir.
- **Düzenlilik ve Taşma**: Sayısal türlerin taşma (overflow) ve sıfırla bölme gibi özel durumlar için özelliklere de erişilebilir.
**Örnek Kullanım:**
```cpp
#include
#includeint main() {
std::cout << "int min: " << std::numeric_limits::min() << std::endl;
std::cout << "int max: " << std::numeric_limits::max() << std::endl;
std::cout << "float epsilon: " << std::numeric_limits::epsilon() << std::endl;return 0;
}```
---
Bu alıştırma (Exercise 01), serileştirme (`serialization`) ve ters serileştirme (`deserialization`) işlemlerini gerçekleştiren bir `Serializer` sınıfı yazmanızı istiyor. Ayrıca, bu sınıfın doğru çalıştığını test eden bir program yazmanız gerekiyor.
İşte adım adım ne yapmanız gerektiği:
**1. Serializer Sınıfını Oluştur**
- `Serializer` sınıfı, kullanıcı tarafından hiçbir şekilde örneklenemez (`initializable`) olmamalıdır. Yani, sınıfın constructor'ları private olmalıdır.
- Sınıf, iki `static` metoda sahip olmalıdır:
- `uintptr_t serialize(Data* ptr);`: Bir `Data pointer`'ını alır ve onu `uintptr_t` türüne (işaretsiz bir tamsayı türü) dönüştürür.
- `Data* deserialize(uintptr_t raw);`: Bir `uintptr_t` türündeki değeri alır ve onu `Data*` türüne (yani bir Data pointer'ına) dönüştürür.
**2. Data Yapısını Oluştur**
- `Data` adında bir yapı (`struct`) oluşturun. Bu yapı boş olmamalıdır, yani en az bir veri üyesine (data member) sahip olmalıdır. Örneğin:
- ```cpp
struct Data {
int a;
double b;
};
```**3. Test Programını Yaz**
- `main` fonksiyonunda aşağıdaki adımları takip edin:
- Bir `Data` nesnesi oluşturun ve içine veri atayın.
- Bu nesnenin adresini `serialize()` fonksiyonuna gönderin ve dönen `uintptr_t` değerini kaydedin.
- Bu `uintptr_t` değerini `deserialize()` fonksiyonuna gönderin ve dönen `Data*` pointer'ını kaydedin.
- Orijinal pointer ile `deserialize()` sonucu dönen pointer'ın aynı adresi gösterdiğini kontrol edin.
- Data nesnesinin veri üyelerini ekrana yazdırarak doğru çalıştığını doğrulayın.
---
`static` metodlar, belirli bir sınıfın üyesi olan ancak o sınıfın belirli bir nesnesine bağlı olmayan metodlardır. Yani, `static metodlar` nesne oluşturmadan çağrılabilir. Bunun sebebi, static metodların sınıf düzeyinde tanımlanması ve sınıfın herhangi bir örneğine (instance) bağlı olmamasıdır.
- **Nesneye Bağlı Değildir:** `Static metodlar`, sınıfa ait olup belirli bir nesneye ihtiyaç duymaz.
- **Sadece Static Üyelere Erişebilir:** `Static metodlar`, sınıf içindeki yalnızca `static` değişkenlere ve diğer static metodlara erişebilir.
- **Sınıf Adı ile Çağrılır:** Bir nesne oluşturmadan, doğrudan sınıf adı üzerinden çağrılır:
- ```cpp
SinifAdi::MetodAdi();
```- **this Pointer'ı Kullanamaz:** `Static metodlar` nesneye bağlı olmadığı için `this` pointer'ı içermez.
---
`reinterpret_cast`, bir tür dönüşüm (`type casting`) operatörüdür. Bu operatör, bir türü tamamen farklı bir türe dönüştürmek için kullanılır. Ancak, diğer tür dönüşüm operatörlerinden (örneğin, `static_cast`, `dynamic_cast`, `const_cast`) farklı olarak, `reinterpret_cast` çok daha güçlü ve tehlikeli bir operatördür. Çünkü bu operatör, derleyiciye "bu veriyi başka bir tür olarak yorumla" der ve herhangi bir tür kontrolü yapmaz.
`reinterpret_cast` aşağıdaki durumlarda kullanılır:
- **Pointer Türleri Arasında Dönüşüm:** Bir pointer'ı başka bir pointer türüne dönüştürmek.
- Örneğin, `int*` türündeki bir pointer'ı `double*` türüne dönüştürmek.
- **Pointer ile Tamsayı Arasında Dönüşüm:** Bir pointer'ı tamsayıya veya bir tamsayıyı pointer'a dönüştürmek.
- Örneğin, bir pointer'ın bellek adresini `uintptr_t` türünde bir tamsayıya çevirmek.
- **Farklı Türler Arasında Dönüşüm:** İlişkisiz türler arasında dönüşüm yapmak.
- Örneğin, bir sınıf pointer'ını tamamen farklı bir sınıf pointer'ına dönüştürmek.
**Nasıl Kullanılır?**
reinterpret_cast'in genel kullanım şekli şöyledir:
```cpp
reinterpret_cast(ifade);
```- **YeniTür:** Dönüştürmek istediğiniz tür.
- **ifade:** Dönüştürülecek değer veya ifade.
---
`uintptr_t`, bir tamsayı türüdür ve işaretçileri (pointer) tutabilecek kadar büyük bir tamsayı türü olarak tanımlanır. Bu tür, `` veya `` başlık dosyasında tanımlıdır.
- **Taşınabilirlik sağlar:** `uintptr_t`, platform bağımsız bir şekilde, işaretçileri tamsayıya çevirmek için kullanılır.
- **İşaretçi genişliği ile aynıdır:** `uintptr_t`, kullanılan sistemin işaretçi boyutuna eşittir. Örneğin:
- `32-bit` sistemde `uintptr_t` `32 bit` olur.
- `64-bit` sistemde `uintptr_t` `64 bit` olur.- **İşaretçi dönüşümlerinde güvenli kullanılır:** İşaretçiyi tamsayıya çevirmek ve tekrar işaretçiye dönüştürmek için kullanılır.
---
Bu alıştırmada, yalnızca genel (public) sanal bir yıkıcıya (destructor) sahip olan bir `Base` sınıfı oluşturmalısınız. Ayrıca, `Base` sınıfından türeyen `A`, `B` ve `C` adında üç boş sınıf oluşturmalısınız. Bu dört sınıfın Ortodoks Kanonik Form'da (Orthodox Canonical Form) olması gerekmez.
Aşağıdaki işlevleri uygulamalısınız:- `Base * generate(void);`
- `A`, `B` veya `C` türünden bir nesneyi rastgele oluşturmalı ve bunu `Base` türünde bir işaretçi olarak döndürmelidir. Rastgele seçim için istediğiniz yöntemi kullanabilirsiniz.- `void identify(Base* p);`
- `p` tarafından işaret edilen nesnenin gerçek türünü yazdırmalıdır (`"A"`, `"B"` veya `"C"`).- `void identify(Base& p);`
- `p` değişkeninin işaret ettiği nesnenin gerçek türünü yazdırmalıdır (`"A"`, `"B"` veya `"C"`). Ancak, bu fonksiyonun içinde işaretçi (`pointer`) kullanmak yasaktır.**Yasaklı Fonksiyonlar ve Kütüphaneler**
- `std::typeinfo` kütüphanesi kullanılamaz.
- `typeid` operatörü yasaktır.---
`dynamic_cast`, C++ dilinde çalışma zamanında (`runtime`) türetilmiş bir sınıfın gerçek türünü belirlemek için kullanılan bir `cast` operatörüdür. Özellikle polimorfizm (çok biçimlilik) kullanıldığında, bir `Base` sınıf işaretçisini veya referansını türetilmiş sınıflara güvenli bir şekilde dönüştürmek için kullanılır.
### Kullanımı
```cpp
Base *basePtr = new A();
A *aPtr = dynamic_cast(basePtr);
if (aPtr)
std::cout << "Nesne A türündedir." << std::endl;
else
std::cout << "Nesne A türünde değildir." << std::endl;
```### dynamic_cast Kullanım Koşulları
- `dynamic_cast`, yalnızca en az bir sanal (`virtual`) fonksiyona sahip sınıflarda çalışır. Bu yüzden `Base` sınıfının en az bir sanal fonksiyona sahip olması gerekir.
- Eğer `dynamic_cast` başarısız olursa:
- İşaretçi (`pointer`) kullanılıyorsa, `nullptr` döndürülür.
- Referans (`reference`) kullanılıyorsa, `std::bad_cast` istisnası (`exception`) fırlatılır.Bu alıştırmada, `dynamic_cast` kullanarak `Base` türündeki bir işaretçi ve referansı `A`, `B` ve `C` türüne dönüştürüp, tür belirleme işlemi yapmanız gerekmektedir.
---
Tür Dönüştürme Operatörleri Tablo
| **Operatör** | **Kullanım Amacı** | **Örnek Kullanım** | **Ek Açıklamalar** |
|----------------------|----------------------|----------------------|----------------------|
| `static_cast` | İlişkili türler arasında güvenli dönüşüm yapar | `int a = static_cast(3.14);` | Türetilmiş sınıftan temel sınıfa dönüşüm için kullanılır. |
| `dynamic_cast` | Çalışma zamanında tür kontrolü yapar | `Base* b = dynamic_cast(derivedPtr);` | Yalnızca polimorfik sınıflar için kullanılır. Başarısız olursa `nullptr` döner. |
| `const_cast` | `const` veya `volatile` niteliklerini kaldırır | `const int* p; int* q = const_cast(p);` | `const` kaldırıldığı için değişken değiştirilebilir hale gelir. |
| `reinterpret_cast` | Tür güvenliği olmadan dönüşüm yapar | `void* ptr = reinterpret_cast(someInt);` | İşaretçiler ve türler arasında dönüşüm yapar, ancak güvenli değildir. |---
2025 This project was created by Derya ACAR.