Sobes.tech
Middle+
304

Niyə vektor ondan miras alınarsa, pis işləyəcək?

AI-dan cavab

sobes.tech Süni İntellekt

std::vector-dən irsənmə tövsiyə edilmir, çünki virtual destruktorlar və digər virtual funksiyalar mövcud deyil, bu da LSP (Liskov Substitutsiya Prinsipi) pozur və polimorf istifadə zamanı problemlərə səbəb olur.

Məsələn, problemlər:

  1. Slicing problemi: Əgər törəmə sinif obyektini dəyər və ya referans vasitəsilə əsas sinif std::vector-ə ötürsəniz, törəmə sinifə aid məlumatlar və davranışlar itəcək.

    #include <vector>
    #include <iostream>
    
    class MyVector : public std::vector<int> {
    public:
        int my_data = 100;
        // Virtual destruktor yoxdur
        ~MyVector() {
            std::cout << "MyVector destruktor" << std::endl;
        }
    };
    
    void process_vector(std::vector<int> vec) {
        // Dəyər ilə qəbul edilir - slicing baş verir
        // MyVector destruktoru çağrılmayacaq
        std::cout << "std::vector emalı" << std::endl;
    }
    
    int main() {
        MyVector mv;
        mv.push_back(1);
        process_vector(mv); // MyVector obyektinin slicing-i
        return 0;
    } // Yalnız std::vector destruktoru çağrılır
    
  2. Virtual destruktorun olmaması: Əgər törəmə sinif obyektini əsas sinif göstəricisi ilə silsəniz, törəmə sinifin destruktoru çağrılmayacaq, bu da resurs sızmasına səbəb ola bilər.

    #include <vector>
    #include <iostream>
    #include <memory> // unique_ptr üçün
    
    class DerivedVector : public std::vector<int> {
    public:
        int* resource;
        DerivedVector() : std::vector<int>(), resource(new int) {
            std::cout << "DerivedVector konstruktor" << std::endl;
        }
        // Virtual destruktor yoxdur
        ~DerivedVector() {
            std::cout << "DerivedVector destruktor" << std::endl;
            delete resource; // Çağrılmaya bilər
        }
    };
    
    int main() {
        // Əsas sinif göstəricisi ilə silmə
        std::vector<int>* base_ptr = new DerivedVector();
        // delete base_ptr ilə yalnız std::vector destruktoru çağrılır,
        // DerivedVector destruktoru çağrılmır, resource sızması
        delete base_ptr;
    
        // unique_ptr nümunəsi
        // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>();
        // Scope-dan çıxanda, unique_ptr delete çağıracaq və delete base_ptr; ilə eynidir.
        // Bu, vector virtual destruktoru yoxdursa, eyni problemi yaradar.
    
        return 0;
    } // resource üçün ayrılmış yaddaş sərbəst buraxılmayacaq
    
  3. Konstruktorlar: std::vector-in konstruktorlarının (məsələn, kopyalama və köçürmə konstruktorları) davranışı, əgər törəmə sinif öz vəziyyətini və ya logikasını əlavə edirsə, gözləntilərə cavab verməyə bilər.

std::vector-dən irsənməyin yerinə, ən yaxşı yanaşmalar:

  • Kompozisiya: std::vector-i sinifin üzvü kimi istifadə et. Bu, interfeys və davranışı idarə etməyə imkan verir, std::vector-i içində istifadə etməklə.
    #include <vector>
    #include <iostream>
    
    class MyContainer {
    private:
        std::vector<int> data;
        int my_extra_data = 100;
    public:
        void add(int val) {
            data.push_back(val);
        }
        const std::vector<int>& get_data() const { // Giriş üçün
            return data;
        }
        // MyContainer destruktoru, data destruktorunu düzgün çağıracaq
        ~MyContainer() {
             std::cout << "MyContainer destruktor" << std::endl;
        }
    };
    
    int main() {
        MyContainer mc;
        mc.add(1);
        std::cout << "Data ölçüsü: " << mc.get_data().size() << std::endl;
        return 0;
    } // MyContainer destruktoru çağrılır, o da std::vector destruktorunu çağırır
    
  • Boş funksiyalar və algoritmlər: std::vector-in funksionallığını adi funksiyalar və ya standart algoritmlərlə genişləndirin.

Bu yanaşmalar daha çevik, daha təhlükəsiz və C++-də OOP və kitabxana dizayn prinsiplərinə uyğundur. Standart konteynerlər əsas sinif kimi istifadə üçün nəzərdə tutulmayıb.