Miks vektor töötab halvasti, kui sellest pärida?
sobes.tech AI
Vastus AI-lt
Pärilitus std::vector-ist ei soovitata, kuna puuduvad virtuaalsed destruktorid ja teised virtuaalsed funktsioonid, mis rikuvad LSP-d (Liskovi asenduspõhimõtet) ning põhjustavad probleeme polümorfses kasutuses.
Näited probleemidest:
-
Lõikamise (slicing) probleem: Kui edastate päriliku klassi objekti väärtuse või viitena baasklassile
std::vector, kaovad päriliku klassi spetsiifilised andmed ja käitumine.#include <vector> #include <iostream> class MyVector : public std::vector<int> { public: int my_data = 100; // Puudub virtuaalne destruktor ~MyVector() { std::cout << "MyVector destruktor" << std::endl; } }; void process_vector(std::vector<int> vec) { // Võtab väärtusena - toimub lõikamine // MyVector destruktor ei kutsuta std::cout << "std::vector töötlemine" << std::endl; } int main() { MyVector mv; mv.push_back(1); process_vector(mv); // Toimub MyVector objekti lõikamine return 0; } // Siin kutsutakse välja ainult std::vector destruktor -
Puudub virtuaalne destruktor: Kui kustutate päriliku klassi objekti baasklassi viitena
std::vector, päriliku klassi destruktorit ei kutsuta, mis võib põhjustada ressursside lekkimist.#include <vector> #include <iostream> #include <memory> // unique_ptr jaoks class DerivedVector : public std::vector<int> { public: int* resource; DerivedVector() : std::vector<int>(), resource(new int) { std::cout << "DerivedVector konstruktor" << std::endl; } // Puudub virtuaalne destruktor ~DerivedVector() { std::cout << "DerivedVector destruktor" << std::endl; delete resource; // Võib jääda välja } }; int main() { // Kustutamine baasklassi viitega std::vector<int>* base_ptr = new DerivedVector(); // delete base_ptr - kutsutakse ainult std::vector destruktor, // DerivedVector destruktor ei kutsuta, toimub ressursside lekkimine delete base_ptr; // Näide unique_ptr-iga // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>(); // up->push_back(5); // Kui unique_ptr väljub ulatusest, kutsub ta delete- i peale base_ptr. // See on ekvivalent delete-ile ja võib põhjustada sama probleemi, kui vectoril puudub virtuaalne destruktor. return 0; } // Ressursi mälu ei vabastata -
Konstruktorid:
std::vectorkonstruktorid (nt koopiakonstruktor, liigutuskonstruktor) võivad mitte vastata ootustele päriliku klassi puhul, kui see lisab oma oleku või loogika.
Asenduseks std::vector-ist pärimine on paremad:
- Koostöö: Kasutada
std::vectorklassi liikmena. See võimaldab kontrollida liidest ja käitumist, kasutadesstd::vector-i sees.#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 { // Pääs andmete saamiseks return data; } // MyContainer destruktor kutsub õigesti välja data destruktor ~MyContainer() { std::cout << "MyContainer destruktor" << std::endl; } }; int main() { MyContainer mc; mc.add(1); std::cout << "Andmete suurus: " << mc.get_data().size() << std::endl; return 0; } // MyContainer destruktor kutsutakse välja, mis omakorda kutsub välja std::vector destruktor - Vabad funktsioonid ja algoritmid: Laiendada
std::vectorfunktsionaalsust tavaliste funktsioonide või standardsete algoritmide abil.
Need lähenemised on paindlikumad, turvalisemad ja vastavad OOP ning raamatukogude disaini põhimõtetele. Standardkonteinerid ei ole mõeldud alusklassideks.