Sobes.tech
Middle+

Эмне үчүн вектор мурас алынса, ал начар иштейт?

sobes.tech AI

AIден жооп

std::vector-тен мурас калтыруу сунушталбайт, анткени виртуалдык деструкторлор жана башка виртуалдык функциялар жок, бул LSP (Лисковдун алмаштыруу принциби) бузулат жана полиморфтук колдонууда көйгөйлөргө алып келет.

Маселелердин мисалдары:

  1. Кесүү (slicing) маселеси: Эгер std::vector базалык класска көрсөткүч же мааниде берилсе, мурас класстын өзгөчө маалыматтары жана жүрүм-туруму жоголот.

    #include <vector>
    #include <iostream>
    
    class MyVector : public std::vector<int> {
    public:
        int my_data = 100;
        // Виртуалдык деструктор жок
        ~MyVector() {
            std::cout << "MyVector деструктору" << std::endl;
        }
    };
    
    void process_vector(std::vector<int> vec) {
        // Мааниде кабыл алуу - кесүү болот
        // MyVector деструктору чакырылбайт
        std::cout << "std::vector иштетүү" << std::endl;
    }
    
    int main() {
        MyVector mv;
        mv.push_back(1);
        process_vector(mv); // MyVector объектисин кесүү
        return 0;
    } // Бул жерде only std::vector деструктору чакырылат
    
  2. Виртуалдык деструктордун жоктугу: Эгер мурас класстын объектин базалык класска көрсөткүч аркылуу өчүрсөңүз, мурас класстын деструктору чакырылбайт, бул ресурстардын агып кетишине алып келет.

    #include <vector>
    #include <iostream>
    #include <memory> // unique_ptr үчүн
    
    class DerivedVector : public std::vector<int> {
    public:
        int* resource;
        DerivedVector() : std::vector<int>(), resource(new int) {
            std::cout << "DerivedVector конструктору" << std::endl;
        }
        // Виртуалдык деструктор жок
        ~DerivedVector() {
            std::cout << "DerivedVector деструктору" << std::endl;
            delete resource; // Чакырылбай калышы мүмкүн
        }
    };
    
    int main() {
        // Базалык класска көрсөткүч аркылуу өчүрүү
        std::vector<int>* base_ptr = new DerivedVector();
        // delete base_ptr - only std::vector деструктору чакырылат,
        // DerivedVector деструктору чакырылбайт, resource чыгат
        delete base_ptr;
    
        // Мисал with unique_ptr
        // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>();
        // up->push_back(5);
        // unique_ptr-тин аяктаганда, ал delete чакыргандай болот, бул ошол эле көйгөйгө алып келет, эгер vector виртуалдык деструкторго ээ болбосо.
    
        return 0;
    } // Resource үчүн бөлүнгөн эс тутум бошотулбай калат
    
  3. Конструкторлор: std::vector конструкторлору (мисалы, көчүрүү, которуу) мурас класстын күтүүлөрүнө туура келбеши мүмкүн, эгер ал өзүнүн абалын же логикасын кошсо.

std::vectorтен мурас алуудан алыс болуу үчүн, эң жакшы ыкмалар:

  • Композиция: std::vectorти класс мүчөсү катары колдонуу. Бул жаңы класстын интерфейси жана жүрүм-турумун контролдоого мүмкүндүк берет, std::vector ички колдонулат.
    #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 { // Кирүү мүмкүнчүлүгүн берүү
            return data;
        }
        // MyContainer деструктору туура иштейт жана data деструкторун чакырат
        ~MyContainer() {
             std::cout << "MyContainer деструктору" << std::endl;
        }
    };
    
    int main() {
        MyContainer mc;
        mc.add(1);
        std::cout << "Даналардын өлчөмү: " << mc.get_data().size() << std::endl;
        return 0;
    } // MyContainer деструктору чакырылат, ал өз кезегинде std::vector деструкторун чакырат
    
  • Бос функциялар жана алгоритмдер: std::vector функционалдуулугун жөнөкөй функциялар менен кеңейтип же стандарттык алгоритмдерди колдонуу.

Бул ыкмалар көбүрөөк ийкемдүү, коопсуз жана C++ ООП жана китепкана долбоорлоо принциптерине ылайыктуу. Стандарттык контейнерлер негизги класстар катары колдонууга арналган эмес.