79 / 90

C++ Type Conversion Operators

C++ tur o'zgartirish operatorlari

Nomlangan translatsiyalardan foydalanish boshqa usullarga nisbatan C++ da type conversion ning xavfsizroq va ishonchli usuli hisoblanadi. C++ da to'rtta asosiy nomli tip-casting ifodalari mavjud:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast

C++ static_cast

static_cast dan float dan int ga aylantirish kabi standart turdagi konvertatsiyalar uchun foydalanamiz.

Keling, bir misolni ko'rib chiqaylik.

example.cpp
#include <iostream>
using namespace std;

int main() {
    float my_float = 3.14;
    
    // floatni int ga aylantiring
    int my_int = static_cast<int>(my_float);
    cout << "Float: " << my_float << " -> Int: " << my_int << endl;

    return 0;
}

Chiqish

kod
Float: 3.14 -> Int: 3

static_cast<int>(my_float) ifodasi my_float-da saqlangan float qiymatini butun songa aylantiradi va uni my_int-da saqlaydi.

Suzuvchi nuqta qiymatlari o'nlik komponentlarga ega bo'lishi va butun sonlar bo'lmasligi sababli, bu konvertatsiya o'nlik qismini olib tashlaydi va 3,14 ni 3 ga aylantiradi.

C++ dynamic_cast

Biz asosan polymorphic tipidagi konvertatsiyalar uchun dynamic_cast dan foydalanamiz, ayniqsa inheritance ierarxiyasi bilan ishlashda. U odatda pointer tayanch sinfi olingan sinf ko‘rsatkichiga aylantirilishi kerak bo‘lgan stsenariylarda qo‘llaniladi.

Keling, bir misolni ko'rib chiqaylik.

example.cpp
#include <iostream>
using namespace std;

class Base {
public:
    // 
    virtual void print() {
        cout << "Base class" << endl;
    }
};

class Derived : public Base {
public:
    // tayanch sinfni bekor qiluvchi olingan sinfni chop etish funksiyasi
    void print() override {
        cout << "Derived class" << endl;
    }
};

int main() {
    // asosiy sinf ko'rsatkichini yarating
    // Derived ob'ektga ishora qilish
    Base *base_ptr = new Derived();
    
    // uzatish uchun dynamic_cast dan foydalaning
    // Olingan ko'rsatkichga asosiy ko'rsatkich
    Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
    
    // olingan ko'rsatkich orqali chop etish funksiyasini chaqiring
    if (derived_ptr) {
        derived_ptr->print();
    }

    // dinamik ravishda ajratilgan ob'ektni o'chirish
    delete base_ptr;

    return 0;
}

Chiqish

kod
Derived class

Bu misolda,

  • Biz Base tayanch sinfini va Derived Base dan meros qilib olingan Derived sinfini aniqladik.
  • main() da biz Derived obyektiga ishora qiluvchi Base* tipidagi base_ptr ko‘rsatkichini yaratdik.
  • Keyin biz dynamic_cast -dan base_ptr -ni Derived* ko'rsatkichiga uzatish va uni derived_ptr -ga belgilash uchun foydalandik.
  • Nihoyat, biz print() funksiyasini derived_ptr orqali chaqirdik, ya'ni dinamik translatsiyadan so'ng Base sinf ko'rsatkichi orqali Derived sinf funksiyasiga kirishimiz mumkin.

[!NOTE] Agar asosiy sinf ko'rsatkichi olingan sinf ob'ektiga ishora qilmasa, dynamic_cast nullptr ni qaytaradi.

C++ const_cast

variable dan const kvalifikatsiyasini olib tashlash uchun const_cast dan foydalanamiz.

const_cast -dan foydalanishimiz mumkin bo'lgan umumiy stsenariylardan biri functions -ga ega bo'lgan uchinchi tomon kutubxonalari bilan ishlash bo'lib, ular doimiy bo'lmagan ko'rsatkichlarni argument sifatida qabul qiladi, ammo biz const ma'lumotlarini o'tkazishimiz kerak.

Keling, bir misolni ko'rib chiqaylik.

example.cpp
#include <iostream>
using namespace std;

// const bo'lmagan ko'rsatkichni oladigan funksiya
void modify_data(int* data) {
    // ma'lumotlarni o'zgartirish
    *data *= 2;
}

int main() {
    int x = 10;
    
    // x o'zgaruvchisi uchun const ko'rsatkichi
    const int* ptr = &x;

    // const_cast dan foydalaning
    // const kvalifikatsiyasini olib tashlang va o'zgartirishga ruxsat bering
    int* mutable_ptr = const_cast<int*>(ptr);

    // funksiyani chaqiring
    modify_data(mutable_ptr);

    // 
    cout << "Modified value: " << x << endl;

    return 0;
}

Chiqish

kod
Modified value: 20

Ushbu misolda biz const_cast ifodasidan const kvalifikatorini argument sifatida konst bo'lmagan ko'rsatgichni qabul qiluvchi funksiya orqali o'tkazish uchun ko'rsatgichdan olib tashladik.

Bu yerga,

-modify_data(int* data) : argument sifatida const bo'lmagan ko'rsatgichni oladigan funksiya -ptr: bu modify_data ga o'tishimiz kerak bo'lgan konst ko'rsatkichi

  • const_cast<int*>(ptr): casts ptr as a non-const pointer and assigns it to mutable_ptr

C++ reinterpret_cast

reinterpret_cast bir ko'rsatkich turini boshqa ko'rsatkich turiga yoki bitta mos yozuvlar turini boshqa mos yozuvlar turiga aylantirish uchun ishlatiladi.

static_cast dan farqli o'laroq, reinterpret_cast aslida ma'lumotlar turlarini o'zgartirmaydi, lekin kompilyatsiya vaqtida bir ko'rsatkich turini boshqasi sifatida qayta talqin qiladi.

Keling, bir misolni ko'rib chiqaylik.

example.cpp
#include <iostream>
using namespace std;

int main() {
    // butun sonli o'zgaruvchini yarating
    int x = 67;

    // butun songa ko'rsatkich
    int* ptr_to_int = &x;

    // ko'rsatgichni butun songa qayta talqin qilish
    // charga ko'rsatkich sifatida
    char* ptr_to_char = reinterpret_cast<char*>(ptr_to_int);

    // qo'sh ko'rsatgichga murojaat qiling
    // dastlab butun sonni xuddi dublni o'z ichiga olgandek ushlab turadi
    cout << "Dereferencing ptr_to_char: " << *ptr_to_char << endl;

    return 0;
}

Chiqish

kod
Dereferencing ptr_to_char: C

Bu yerda biz reinterpret_cast dan dastlab butun songa ishora qilgan ptr_to_int ko‘rsatkichini belgiga ko‘rsatgich sifatida qayta talqin qilish uchun foydalandik.

Bu shuni anglatadiki, ptr_to_int tomonidan ko'rsatilgan xotira joyi hali ham butun son qiymatiga ega. Ammo u xarakter sifatida ko'rib chiqiladi.

[!NOTE] reinterpret_cast allows for almost any pointer or integer type conversion without any type safety checks. This can result in undefined behavior. So, reinterpret_cast should be used with caution.