რატომ იმუშავებს ვექტორი ცუდად, თუ მასგან მემკვიდრეობით მიიღება?
sobes.tech AI
პასუხი AI-სგან
std::vector-тан мирас калтыруу сунушталмайт, анткени виртуалдык деструкторлор жана башка виртуалдык функциялар жок, бул LSP (Лисковдун алмаштыруу принциби) бузулат жана полиморфтук колдонууда көйгөйлөргө алып келет.
Маселелердин мисалдары:
-
Кесүү (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 деструктору чакырылат -
Виртуалдык деструктордун жоктугу: Эгер
std::vectorбазалык класска көрсөткүч аркылуу объектти өчүрсөңүз, жакынкы класстын деструктору чакырылбайт, бул ресурстардын чыгышына алып келет.#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 үчүн бөлүнгөн эс тутум бошотулбай калат -
Конструкторлор:
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++ ООП жана китепкана долбоорлоо принциптерине ылайыктуу. Стандарттык контейнерлер негизги класстар катары колдонууга арналган эмес.